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 @@
*
*
* 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)
tm->tm_hour = 0;
tm->tm_min = 0;
tm->tm_sec = 0;
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
#ifdef HAVE_INT64_TIMESTAMP
result = dateVal * USECS_PER_DAY + tz * USECS_PER_SEC;
......@@ -2231,7 +2231,7 @@ time_timetz(PG_FUNCTION_ARGS)
GetCurrentDateTime(tm);
time2tm(time, tm, &fsec);
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
......
......@@ -8,7 +8,7 @@
*
*
* 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,
if (fmask & DTK_M(DTZMOD))
return DTERR_BAD_FORMAT;
*tzp = DetermineLocalTimeZone(tm);
*tzp = DetermineTimeZoneOffset(tm, global_timezone);
}
}
......@@ -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
* 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
* tm_isdst field accordingly, and return the actual timezone offset.
*
......@@ -1632,7 +1632,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
* of mktime(), anyway.
*/
int
DetermineLocalTimeZone(struct pg_tm *tm)
DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
{
int date,
sec;
......@@ -1648,7 +1648,7 @@ DetermineLocalTimeZone(struct pg_tm *tm)
after_isdst;
int res;
if (HasCTZSet)
if (tzp == global_timezone && HasCTZSet)
{
tm->tm_isdst = 0; /* for lack of a better idea */
return CTimeZone;
......@@ -1687,7 +1687,7 @@ DetermineLocalTimeZone(struct pg_tm *tm)
&before_gmtoff, &before_isdst,
&boundary,
&after_gmtoff, &after_isdst,
global_timezone);
tzp);
if (res < 0)
goto overflow; /* failure? */
......@@ -2282,7 +2282,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
tmp->tm_hour = tm->tm_hour;
tmp->tm_min = tm->tm_min;
tmp->tm_sec = tm->tm_sec;
*tzp = DetermineLocalTimeZone(tmp);
*tzp = DetermineTimeZoneOffset(tmp, global_timezone);
tm->tm_isdst = tmp->tm_isdst;
}
......
/* -----------------------------------------------------------------------
* 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
......@@ -2989,7 +2989,7 @@ to_timestamp(PG_FUNCTION_ARGS)
do_to_timestamp(date_txt, fmt, &tm, &fsec);
tz = DetermineLocalTimeZone(&tm);
tz = DetermineTimeZoneOffset(&tm, global_timezone);
if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
ereport(ERROR,
......
......@@ -10,7 +10,7 @@
*
*
* 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)
result = NOEND_ABSTIME;
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
{
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
result = tm2abstime(tm, tz);
}
else
......
......@@ -8,7 +8,7 @@
*
*
* 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)
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]);
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
ereport(ERROR,
......@@ -2124,7 +2124,7 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
julian = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + span->day;
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)
ereport(ERROR,
......@@ -3104,7 +3104,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
}
if (redotz)
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR,
......@@ -3529,7 +3529,7 @@ timestamp_part(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &timestamptz) != 0)
ereport(ERROR,
......@@ -3924,12 +3924,11 @@ interval_part(PG_FUNCTION_ARGS)
/* timestamp_zone()
* Encode timestamp type with specified time zone.
* Returns timestamp with time zone, with the input
* rotated from local time to the specified zone.
* This function is tricky because instead of shifting
* the time _to_ a new time zone, it sets the time to _be_
* the specified timezone. This requires trickery
* of double-subtracting the requested timezone offset.
* This function is just timestamp2timestamptz() except instead of
* shifting to the global timezone, we shift to the specified timezone.
* This is different from the other AT TIME ZONE cases because instead
* of shifting to a _to_ a new time zone, it sets the time to _be_ the
* specified timezone.
*/
Datum
timestamp_zone(PG_FUNCTION_ARGS)
......@@ -3943,11 +3942,12 @@ timestamp_zone(PG_FUNCTION_ARGS)
int len;
struct pg_tm tm;
fsec_t fsec;
bool fail;
if (TIMESTAMP_NOT_FINITE(timestamp))
PG_RETURN_TIMESTAMPTZ(timestamp);
/* Find the specified timezone? */
/* Find the specified timezone */
len = (VARSIZE(zone) - VARHDRSZ>TZ_STRLEN_MAX) ?
TZ_STRLEN_MAX : VARSIZE(zone) - VARHDRSZ;
memcpy(tzname, VARDATA(zone), len);
......@@ -3963,8 +3963,13 @@ timestamp_zone(PG_FUNCTION_ARGS)
}
/* Apply the timezone change */
if (timestamp2tm(timestamp, &tz, &tm, &fsec, NULL, tzp) != 0 ||
tm2timestamp(&tm, fsec, &tz, &result) != 0)
fail = (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, tzp) != 0);
if (!fail)
{
tz = DetermineTimeZoneOffset(&tm, tzp);
fail = (tm2timestamp(&tm, fsec, &tz, &result) != 0);
}
if (fail)
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
......@@ -3972,8 +3977,6 @@ timestamp_zone(PG_FUNCTION_ARGS)
tzname)));
PG_RETURN_NULL();
}
/* Must double-adjust for timezone */
result = dt2local(result, -tz);
PG_RETURN_TIMESTAMPTZ(result);
}
......@@ -4039,7 +4042,7 @@ timestamp2timestamptz(Timestamp timestamp)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
tz = DetermineLocalTimeZone(tm);
tz = DetermineTimeZoneOffset(tm, global_timezone);
if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR,
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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,
extern void DateTimeParseError(int dterr, const char *str,
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 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