aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/timestamp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/timestamp.c')
-rw-r--r--src/backend/utils/adt/timestamp.c139
1 files changed, 73 insertions, 66 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 37308d7451a..035a422bfcc 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.125 2005/06/14 21:04:40 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.126 2005/06/15 00:34:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -142,7 +142,7 @@ timestamp_out(PG_FUNCTION_ARGS)
if (TIMESTAMP_NOT_FINITE(timestamp))
EncodeSpecialTimestamp(timestamp, buf);
- else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf);
else
ereport(ERROR,
@@ -178,7 +178,7 @@ timestamp_recv(PG_FUNCTION_ARGS)
/* rangecheck: see if timestamp_out would like it */
if (TIMESTAMP_NOT_FINITE(timestamp))
/* ok */ ;
- else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -381,7 +381,7 @@ timestamptz_out(PG_FUNCTION_ARGS)
if (TIMESTAMP_NOT_FINITE(dt))
EncodeSpecialTimestamp(dt, buf);
- else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn) == 0)
+ else if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
else
ereport(ERROR,
@@ -419,7 +419,7 @@ timestamptz_recv(PG_FUNCTION_ARGS)
/* rangecheck: see if timestamptz_out would like it */
if (TIMESTAMP_NOT_FINITE(timestamp))
/* ok */ ;
- else if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ else if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -984,9 +984,12 @@ dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
* Returns:
* 0 on success
* -1 on out of range
+ *
+ * If attimezone is NULL, the global timezone (including possblly brute forced
+ * timezone) will be used.
*/
int
-timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn)
+timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn, pg_tz *attimezone)
{
Timestamp date;
Timestamp time;
@@ -997,7 +1000,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
* specified. Go ahead and rotate to the local time zone since we will
* later bypass any calls which adjust the tm fields.
*/
- if (HasCTZSet && (tzp != NULL))
+ if ((attimezone==NULL) && HasCTZSet && (tzp != NULL))
{
#ifdef HAVE_INT64_TIMESTAMP
dt -= CTimeZone * USECS_PER_SEC;
@@ -1050,7 +1053,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
* We have a brute force time zone per SQL99? Then use it without
* change since we have already rotated to the time zone.
*/
- if (HasCTZSet)
+ if ((attimezone==NULL) && HasCTZSet)
{
*tzp = CTimeZone;
tm->tm_isdst = 0;
@@ -1081,7 +1084,7 @@ timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm, fsec_t *fsec, char **tzn
utime = (pg_time_t) dt;
if ((Timestamp) utime == dt)
{
- struct pg_tm *tx = pg_localtime(&utime, global_timezone);
+ struct pg_tm *tx = pg_localtime(&utime, (attimezone!=NULL)?attimezone:global_timezone);
tm->tm_year = tx->tm_year + 1900;
tm->tm_mon = tx->tm_mon + 1;
@@ -1926,7 +1929,7 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
*tm = &tt;
fsec_t fsec;
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -2005,7 +2008,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
*tm = &tt;
fsec_t fsec;
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -2332,8 +2335,8 @@ timestamp_age(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL) == 0 &&
- timestamp2tm(dt2, NULL, tm2, &fsec2, NULL) == 0)
+ if (timestamp2tm(dt1, NULL, tm1, &fsec1, NULL, NULL) == 0 &&
+ timestamp2tm(dt2, NULL, tm2, &fsec2, NULL, NULL) == 0)
{
fsec = (fsec1 - fsec2);
tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
@@ -2446,8 +2449,8 @@ timestamptz_age(PG_FUNCTION_ARGS)
result = (Interval *) palloc(sizeof(Interval));
- if (timestamp2tm(dt1, &tz1, tm1, &fsec1, &tzn) == 0 &&
- timestamp2tm(dt2, &tz2, tm2, &fsec2, &tzn) == 0)
+ if (timestamp2tm(dt1, &tz1, tm1, &fsec1, &tzn, NULL) == 0 &&
+ timestamp2tm(dt2, &tz2, tm2, &fsec2, &tzn, NULL) == 0)
{
fsec = fsec1 - fsec2;
tm->tm_sec = tm1->tm_sec - tm2->tm_sec;
@@ -2750,7 +2753,7 @@ timestamp_trunc(PG_FUNCTION_ARGS)
if (type == UNITS)
{
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -2881,7 +2884,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
if (type == UNITS)
{
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3271,7 +3274,7 @@ timestamp_part(PG_FUNCTION_ARGS)
if (type == UNITS)
{
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3405,7 +3408,7 @@ timestamp_part(PG_FUNCTION_ARGS)
* convert to timestamptz to produce consistent
* results
*/
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3425,7 +3428,7 @@ timestamp_part(PG_FUNCTION_ARGS)
break;
}
case DTK_DOW:
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3433,7 +3436,7 @@ timestamp_part(PG_FUNCTION_ARGS)
break;
case DTK_DOY:
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3496,7 +3499,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
if (type == UNITS)
{
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3631,7 +3634,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
break;
case DTK_DOW:
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3639,7 +3642,7 @@ timestamptz_part(PG_FUNCTION_ARGS)
break;
case DTK_DOY:
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3815,38 +3818,40 @@ timestamp_zone(PG_FUNCTION_ARGS)
{
text *zone = PG_GETARG_TEXT_P(0);
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
- TimestampTz result;
+ Timestamp result;
int tz;
- int type,
- val;
- char *lowzone;
+ pg_tz *tzp;
+ char tzname[TZ_STRLEN_MAX+1];
+ int len;
+ struct pg_tm tm;
+ fsec_t fsec;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
- lowzone = downcase_truncate_identifier(VARDATA(zone),
- VARSIZE(zone) - VARHDRSZ,
- false);
-
- type = DecodeSpecial(0, lowzone, &val);
-
- if (type == TZ || type == DTZ)
- {
- tz = -(val * 60);
-
- result = dt2local(timestamp, tz);
- }
- else
- {
+ /* Find the specified timezone? */
+ len = (VARSIZE(zone)-VARHDRSZ>TZ_STRLEN_MAX)?TZ_STRLEN_MAX:(VARSIZE(zone)-VARHDRSZ);
+ memcpy(tzname,VARDATA(zone),len);
+ tzname[len] = 0;
+ tzp = pg_tzset(tzname);
+ if (!tzp) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("time zone \"%s\" not recognized",
- lowzone)));
-
+ errmsg("time zone \"%s\" not recognised",
+ tzname)));
PG_RETURN_NULL();
}
- PG_RETURN_TIMESTAMPTZ(result);
+ /* Apply the timezone change */
+ if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 ||
+ tm2timestamp(&tm, fsec, NULL, &result) != 0) {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not convert to time zone \"%s\"",
+ tzname)));
+ PG_RETURN_NULL();
+ }
+ PG_RETURN_TIMESTAMPTZ(timestamp2timestamptz(result));
} /* timestamp_zone() */
/* timestamp_izone()
@@ -3906,7 +3911,7 @@ timestamp2timestamptz(Timestamp timestamp)
else
{
- if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
+ if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3941,7 +3946,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
else
{
- if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
+ if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
@@ -3950,7 +3955,6 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
}
-
PG_RETURN_TIMESTAMP(result);
}
@@ -3966,31 +3970,34 @@ timestamptz_zone(PG_FUNCTION_ARGS)
Timestamp result;
int tz;
- int type,
- val;
- char *lowzone;
+ pg_tz *tzp;
+ char tzname[TZ_STRLEN_MAX];
+ int len;
+ struct pg_tm tm;
+ fsec_t fsec = 0;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_NULL();
- lowzone = downcase_truncate_identifier(VARDATA(zone),
- VARSIZE(zone) - VARHDRSZ,
- false);
-
- type = DecodeSpecial(0, lowzone, &val);
+ /* Find the specified zone */
+ len = (VARSIZE(zone)-VARHDRSZ>TZ_STRLEN_MAX)?TZ_STRLEN_MAX:(VARSIZE(zone)-VARHDRSZ);
+ memcpy(tzname,VARDATA(zone),len);
+ tzname[len] = 0;
+ tzp = pg_tzset(tzname);
- if (type == TZ || type == DTZ)
- {
- tz = val * 60;
+ if (!tzp) {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("time zone \"%s\" not recognized", tzname)));
- result = dt2local(timestamp, tz);
+ PG_RETURN_NULL();
}
- else
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("time zone \"%s\" not recognized", lowzone)));
+ if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 ||
+ tm2timestamp(&tm, fsec, NULL, &result)) {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("could not to convert to time zone \"%s\"", tzname)));
PG_RETURN_NULL();
}