Created
March 25, 2010 15:20
-
-
Save mcfunley/343663 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* timestamp_pl_interval() | |
* Add a interval to a timestamp data type. | |
* Note that interval has provisions for qualitative year/month and day | |
* units, so try to do the right thing with them. | |
* To add a month, increment the month, and use the same day of month. | |
* Then, if the next month has fewer days, set the day of month | |
* to the last day of month. | |
* To add a day, increment the mday, and use the same time of day. | |
* Lastly, add in the "quantitative time". | |
*/ | |
Datum | |
timestamp_pl_interval(PG_FUNCTION_ARGS) | |
{ | |
Timestamp timestamp = PG_GETARG_TIMESTAMP(0); | |
Interval *span = PG_GETARG_INTERVAL_P(1); | |
Timestamp result; | |
if (TIMESTAMP_NOT_FINITE(timestamp)) | |
result = timestamp; | |
else | |
{ | |
if (span->month != 0) | |
{ | |
struct pg_tm tt, | |
*tm = &tt; | |
fsec_t fsec; | |
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) | |
ereport(ERROR, | |
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), | |
errmsg("timestamp out of range"))); | |
tm->tm_mon += span->month; | |
if (tm->tm_mon > MONTHS_PER_YEAR) | |
{ | |
tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR; | |
tm->tm_mon = ((tm->tm_mon - 1) % MONTHS_PER_YEAR) + 1; | |
} | |
else if (tm->tm_mon < 1) | |
{ | |
tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1; | |
tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR; | |
} | |
/* adjust for end of month boundary problems... */ | |
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) | |
tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]); | |
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0) | |
ereport(ERROR, | |
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), | |
errmsg("timestamp out of range"))); | |
} | |
if (span->day != 0) | |
{ | |
struct pg_tm tt, | |
*tm = &tt; | |
fsec_t fsec; | |
int julian; | |
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) != 0) | |
ereport(ERROR, | |
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), | |
errmsg("timestamp out of range"))); | |
/* Add days by converting to and from julian */ | |
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; | |
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); | |
if (tm2timestamp(tm, fsec, NULL, ×tamp) != 0) | |
ereport(ERROR, | |
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), | |
errmsg("timestamp out of range"))); | |
} | |
timestamp += span->time; | |
result = timestamp; | |
} | |
PG_RETURN_TIMESTAMP(result); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment