Commit c4acbb84 authored by Tom Lane's avatar Tom Lane

timestamptz_trunc() should only recalculate the timezone when truncating

to DAY precision or coarser; leave the timezone alone when precision is
HOUR or less.  This avoids surprises for inputs near a DST transition
time, as per example from Matthew Gabeler-Lee.  (The only reason we
recalculate at all is so that outputs that are supposed to represent
days will come out as local midnight, and that's not relevant for sub-day
precision.)
parent 5ba04cd9
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.113 2004/08/30 02:54:39 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.114 2004/11/01 22:00:30 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2842,6 +2842,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -2842,6 +2842,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
int tz; int tz;
int type, int type,
val; val;
bool redotz = false;
char *lowunits; char *lowunits;
fsec_t fsec; fsec_t fsec;
char *tzn; char *tzn;
...@@ -2872,6 +2873,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -2872,6 +2873,7 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
tm->tm_min = 0; tm->tm_min = 0;
tm->tm_sec = 0; tm->tm_sec = 0;
fsec = 0; fsec = 0;
redotz = true;
break; break;
/* one may consider DTK_THOUSAND and DTK_HUNDRED... */ /* one may consider DTK_THOUSAND and DTK_HUNDRED... */
case DTK_MILLENNIUM: case DTK_MILLENNIUM:
...@@ -2885,12 +2887,14 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -2885,12 +2887,14 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999; tm->tm_year = ((tm->tm_year + 999) / 1000) * 1000 - 999;
else else
tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1; tm->tm_year = -((999 - (tm->tm_year - 1)) / 1000) * 1000 + 1;
/* FALL THRU */
case DTK_CENTURY: case DTK_CENTURY:
/* truncating to the century? as above: -100, 1, 101... */ /* truncating to the century? as above: -100, 1, 101... */
if (tm->tm_year > 0) if (tm->tm_year > 0)
tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99; tm->tm_year = ((tm->tm_year + 99) / 100) * 100 - 99;
else else
tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1; tm->tm_year = -((99 - (tm->tm_year - 1)) / 100) * 100 + 1;
/* FALL THRU */
case DTK_DECADE: case DTK_DECADE:
/* /*
...@@ -2904,18 +2908,26 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -2904,18 +2908,26 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
else else
tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10; tm->tm_year = -((8 - (tm->tm_year - 1)) / 10) * 10;
} }
/* FALL THRU */
case DTK_YEAR: case DTK_YEAR:
tm->tm_mon = 1; tm->tm_mon = 1;
/* FALL THRU */
case DTK_QUARTER: case DTK_QUARTER:
tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1; tm->tm_mon = (3 * ((tm->tm_mon - 1) / 3)) + 1;
/* FALL THRU */
case DTK_MONTH: case DTK_MONTH:
tm->tm_mday = 1; tm->tm_mday = 1;
/* FALL THRU */
case DTK_DAY: case DTK_DAY:
tm->tm_hour = 0; tm->tm_hour = 0;
redotz = true; /* for all cases >= DAY */
/* FALL THRU */
case DTK_HOUR: case DTK_HOUR:
tm->tm_min = 0; tm->tm_min = 0;
/* FALL THRU */
case DTK_MINUTE: case DTK_MINUTE:
tm->tm_sec = 0; tm->tm_sec = 0;
/* FALL THRU */
case DTK_SECOND: case DTK_SECOND:
fsec = 0; fsec = 0;
break; break;
...@@ -2941,7 +2953,8 @@ timestamptz_trunc(PG_FUNCTION_ARGS) ...@@ -2941,7 +2953,8 @@ timestamptz_trunc(PG_FUNCTION_ARGS)
result = 0; result = 0;
} }
tz = DetermineLocalTimeZone(tm); if (redotz)
tz = DetermineLocalTimeZone(tm);
if (tm2timestamp(tm, fsec, &tz, &result) != 0) if (tm2timestamp(tm, fsec, &tz, &result) != 0)
ereport(ERROR, ereport(ERROR,
......
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