Commit 3dbbbbf8 authored by Bruce Momjian's avatar Bruce Momjian

Andrew pointed out that the current fix didn't handle dates that were

near daylight savings time boudaries.  This handles it properly, e.g.

        test=> select '2005-04-03 04:00:00'::timestamp at time zone
        'America/Los_Angeles';
                timezone
        ------------------------
         2005-04-03 07:00:00-04
        (1 row)
parent 6c61b0d9
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.118 2005/07/22 05:03:09 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.119 2005/07/23 14:25:33 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -301,7 +301,7 @@ date2timestamptz(DateADT dateVal) ...@@ -301,7 +301,7 @@ date2timestamptz(DateADT dateVal)
tm->tm_hour = 0; tm->tm_hour = 0;
tm->tm_min = 0; tm->tm_min = 0;
tm->tm_sec = 0; tm->tm_sec = 0;
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC; result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
...@@ -2231,7 +2231,7 @@ time_timetz(PG_FUNCTION_ARGS) ...@@ -2231,7 +2231,7 @@ time_timetz(PG_FUNCTION_ARGS)
GetCurrentDateTime(tm); GetCurrentDateTime(tm);
time2tm(time, tm, &fsec); time2tm(time, tm, &fsec);
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT)); result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.156 2005/07/22 03:46:33 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.157 2005/07/23 14:25:33 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1612,7 +1612,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1612,7 +1612,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
if (fmask & DTK_M(DTZMOD)) if (fmask & DTK_M(DTZMOD))
return DTERR_BAD_FORMAT; return DTERR_BAD_FORMAT;
*tzp = DetermineLocalTimeZone(tm); *tzp = DetermineTimeZoneOffset(tm, global_timezone);
} }
} }
...@@ -1620,10 +1620,10 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1620,10 +1620,10 @@ DecodeDateTime(char **field, int *ftype, int nf,
} }
/* DetermineLocalTimeZone() /* DetermineTimeZoneOffset()
* *
* Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
* tm_sec fields are set, attempt to determine the applicable local zone * tm_sec fields are set, attempt to determine the applicable time zone
* (ie, regular or daylight-savings time) at that time. Set the struct pg_tm's * (ie, regular or daylight-savings time) at that time. Set the struct pg_tm's
* tm_isdst field accordingly, and return the actual timezone offset. * tm_isdst field accordingly, and return the actual timezone offset.
* *
...@@ -1632,7 +1632,7 @@ DecodeDateTime(char **field, int *ftype, int nf, ...@@ -1632,7 +1632,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
* of mktime(), anyway. * of mktime(), anyway.
*/ */
int int
DetermineLocalTimeZone(struct pg_tm *tm) DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
{ {
int date, int date,
sec; sec;
...@@ -1648,7 +1648,7 @@ DetermineLocalTimeZone(struct pg_tm *tm) ...@@ -1648,7 +1648,7 @@ DetermineLocalTimeZone(struct pg_tm *tm)
after_isdst; after_isdst;
int res; int res;
if (HasCTZSet) if (tzp == global_timezone && HasCTZSet)
{ {
tm->tm_isdst = 0; /* for lack of a better idea */ tm->tm_isdst = 0; /* for lack of a better idea */
return CTimeZone; return CTimeZone;
...@@ -1687,7 +1687,7 @@ DetermineLocalTimeZone(struct pg_tm *tm) ...@@ -1687,7 +1687,7 @@ DetermineLocalTimeZone(struct pg_tm *tm)
&before_gmtoff, &before_isdst, &before_gmtoff, &before_isdst,
&boundary, &boundary,
&after_gmtoff, &after_isdst, &after_gmtoff, &after_isdst,
global_timezone); tzp);
if (res < 0) if (res < 0)
goto overflow; /* failure? */ goto overflow; /* failure? */
...@@ -2282,7 +2282,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ...@@ -2282,7 +2282,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmp->tm_hour = tm->tm_hour; tmp->tm_hour = tm->tm_hour;
tmp->tm_min = tm->tm_min; tmp->tm_min = tm->tm_min;
tmp->tm_sec = tm->tm_sec; tmp->tm_sec = tm->tm_sec;
*tzp = DetermineLocalTimeZone(tmp); *tzp = DetermineTimeZoneOffset(tmp, global_timezone);
tm->tm_isdst = tmp->tm_isdst; tm->tm_isdst = tmp->tm_isdst;
} }
......
/* ----------------------------------------------------------------------- /* -----------------------------------------------------------------------
* formatting.c * formatting.c
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.92 2005/07/21 03:56:16 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.93 2005/07/23 14:25:33 momjian Exp $
* *
* *
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
...@@ -2989,7 +2989,7 @@ to_timestamp(PG_FUNCTION_ARGS) ...@@ -2989,7 +2989,7 @@ to_timestamp(PG_FUNCTION_ARGS)
do_to_timestamp(date_txt, fmt, &tm, &fsec); do_to_timestamp(date_txt, fmt, &tm, &fsec);
tz = DetermineLocalTimeZone(&tm); tz = DetermineTimeZoneOffset(&tm, global_timezone);
if (tm2timestamp(&tm, fsec, &tz, &result) != 0) if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
ereport(ERROR, ereport(ERROR,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.141 2005/07/22 19:55:50 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.142 2005/07/23 14:25:33 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -474,7 +474,7 @@ timestamp_abstime(PG_FUNCTION_ARGS) ...@@ -474,7 +474,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
result = NOEND_ABSTIME; result = NOEND_ABSTIME;
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0) else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
{ {
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
result = tm2abstime(tm, tz); result = tm2abstime(tm, tz);
} }
else else
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.143 2005/07/23 02:02:27 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.144 2005/07/23 14:25:34 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2100,7 +2100,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS) ...@@ -2100,7 +2100,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]) 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]); tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0) if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
ereport(ERROR, ereport(ERROR,
...@@ -2124,7 +2124,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS) ...@@ -2124,7 +2124,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day; julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); j2date(julian, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0) if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
ereport(ERROR, ereport(ERROR,
...@@ -3104,7 +3104,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -3104,7 +3104,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
} }
if (redotz) if (redotz)
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &result) != 0) if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR, ereport(ERROR,
...@@ -3529,7 +3529,7 @@ timestamp_part(PG_FUNCTION_ARGS) ...@@ -3529,7 +3529,7 @@ timestamp_part(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); errmsg("timestamp out of range")));
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &timestamptz) != 0) if (tm2timestamp(tm, fsec, &tz, &timestamptz) != 0)
ereport(ERROR, ereport(ERROR,
...@@ -3924,12 +3924,11 @@ interval_part(PG_FUNCTION_ARGS) ...@@ -3924,12 +3924,11 @@ interval_part(PG_FUNCTION_ARGS)
/* timestamp_zone() /* timestamp_zone()
* Encode timestamp type with specified time zone. * Encode timestamp type with specified time zone.
* Returns timestamp with time zone, with the input * This function is just timestamp2timestamptz() except instead of
* rotated from local time to the specified zone. * shifting to the global timezone, we shift to the specified timezone.
* This function is tricky because instead of shifting * This is different from the other AT TIME ZONE cases because instead
* the time _to_ a new time zone, it sets the time to _be_ * of shifting to a _to_ a new time zone, it sets the time to _be_ the
* the specified timezone. This requires trickery * specified timezone.
* of double-subtracting the requested timezone offset.
*/ */
Datum Datum
timestamp_zone(PG_FUNCTION_ARGS) timestamp_zone(PG_FUNCTION_ARGS)
...@@ -3943,11 +3942,12 @@ timestamp_zone(PG_FUNCTION_ARGS) ...@@ -3943,11 +3942,12 @@ timestamp_zone(PG_FUNCTION_ARGS)
int len; int len;
struct pg_tm tm; struct pg_tm tm;
fsec_t fsec; fsec_t fsec;
bool fail;
if (TIMESTAMP_NOT_FINITE(timestamp)) if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp); PG_RETURN_TIMESTAMPTZ(timestamp);
/* Find the specified timezone? */ /* Find the specified timezone */
len = (VARSIZE(zone) - VARHDRSZ>TZ_STRLEN_MAX) ? len = (VARSIZE(zone) - VARHDRSZ>TZ_STRLEN_MAX) ?
TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ; TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ;
memcpy(tzname, VARDATA(zone), len); memcpy(tzname, VARDATA(zone), len);
...@@ -3963,8 +3963,13 @@ timestamp_zone(PG_FUNCTION_ARGS) ...@@ -3963,8 +3963,13 @@ timestamp_zone(PG_FUNCTION_ARGS)
} }
/* Apply the timezone change */ /* Apply the timezone change */
if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 || fail = (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0);
tm2timestamp(&tm, fsec, &tz, &result) != 0) if (!fail)
{
tz = DetermineTimeZoneOffset(&tm, tzp);
fail = (tm2timestamp(&tm, fsec, &tz, &result) != 0);
}
if (fail)
{ {
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
...@@ -3972,8 +3977,6 @@ timestamp_zone(PG_FUNCTION_ARGS) ...@@ -3972,8 +3977,6 @@ timestamp_zone(PG_FUNCTION_ARGS)
tzname))); tzname)));
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
/* Must double-adjust for timezone */
result = dt2local(result, -tz);
PG_RETURN_TIMESTAMPTZ(result); PG_RETURN_TIMESTAMPTZ(result);
} }
...@@ -4039,7 +4042,7 @@ timestamp2timestamptz(Timestamp timestamp) ...@@ -4039,7 +4042,7 @@ timestamp2timestamptz(Timestamp timestamp)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range"))); errmsg("timestamp out of range")));
tz = DetermineLocalTimeZone(tm); tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &result) != 0) if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR, ereport(ERROR,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.55 2005/07/22 03:46:34 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.56 2005/07/23 14:25:34 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -291,7 +291,7 @@ extern int DecodeInterval(char **field, int *ftype, ...@@ -291,7 +291,7 @@ extern int DecodeInterval(char **field, int *ftype,
extern void DateTimeParseError(int dterr, const char *str, extern void DateTimeParseError(int dterr, const char *str,
const char *datatype); const char *datatype);
extern int DetermineLocalTimeZone(struct pg_tm *tm); extern int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp);
extern int EncodeDateOnly(struct pg_tm *tm, int style, char *str); extern int EncodeDateOnly(struct pg_tm *tm, int style, char *str);
extern int EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, int *tzp, int style, char *str); extern int EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, int *tzp, int style, char *str);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment