Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 388e71a

Browse files
committed
Make timetz_zone() stable, and correct a bug for DYNTZ abbreviations.
Historically, timetz_zone() has used time(NULL) as the reference point for deciding whether DST is active. That means its result can change intra-statement, requiring it to be marked VOLATILE (cf. 35979e6). But that definition is pretty inconsistent with the way we deal with timestamps elsewhere. Let's make it use the transaction start time ("now()") as the reference point instead. That lets it be marked STABLE, and also saves a kernel call per invocation. While at it, remove the function's use of pg_time_t and pg_localtime. Those are inconsistent with the other code in this area, which indeed created a bug: timetz_zone() delivered completely wrong answers if the zone was specified by a dynamic TZ abbreviation. (We need to do something about that in the back branches, but the fix will look different from this.) Aleksander Alekseev and Tom Lane Discussion: https://postgr.es/m/CAJ7c6TOMG8zSNEZtCn5SPe+cCk3Lfxb71ZaQwT2F4T7PJ_t=KA@mail.gmail.com
1 parent 78aa616 commit 388e71a

File tree

3 files changed

+16
-16
lines changed

3 files changed

+16
-16
lines changed

src/backend/utils/adt/date.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,9 +1481,7 @@ float_time_overflows(int hour, int min, double sec)
14811481
/* time2tm()
14821482
* Convert time data type to POSIX time structure.
14831483
*
1484-
* For dates within the range of pg_time_t, convert to the local time zone.
1485-
* If out of this range, leave as UTC (in practice that could only happen
1486-
* if pg_time_t is just 32 bits) - thomas 97/05/27
1484+
* Note that only the hour/min/sec/fractional-sec fields are filled in.
14871485
*/
14881486
int
14891487
time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec)
@@ -3029,7 +3027,7 @@ extract_timetz(PG_FUNCTION_ARGS)
30293027

30303028
/* timetz_zone()
30313029
* Encode time with time zone type with specified time zone.
3032-
* Applies DST rules as of the current date.
3030+
* Applies DST rules as of the transaction start time.
30333031
*/
30343032
Datum
30353033
timetz_zone(PG_FUNCTION_ARGS)
@@ -3068,25 +3066,27 @@ timetz_zone(PG_FUNCTION_ARGS)
30683066
}
30693067
else if (type == DYNTZ)
30703068
{
3071-
/* dynamic-offset abbreviation, resolve using current time */
3072-
pg_time_t now = (pg_time_t) time(NULL);
3073-
struct pg_tm *tm;
3069+
/* dynamic-offset abbreviation, resolve using transaction start time */
3070+
TimestampTz now = GetCurrentTransactionStartTimestamp();
3071+
int isdst;
30743072

3075-
tm = pg_localtime(&now, tzp);
3076-
tz = DetermineTimeZoneAbbrevOffset(tm, tzname, tzp);
3073+
tz = DetermineTimeZoneAbbrevOffsetTS(now, tzname, tzp, &isdst);
30773074
}
30783075
else
30793076
{
30803077
/* try it as a full zone name */
30813078
tzp = pg_tzset(tzname);
30823079
if (tzp)
30833080
{
3084-
/* Get the offset-from-GMT that is valid today for the zone */
3085-
pg_time_t now = (pg_time_t) time(NULL);
3086-
struct pg_tm *tm;
3081+
/* Get the offset-from-GMT that is valid now for the zone */
3082+
TimestampTz now = GetCurrentTransactionStartTimestamp();
3083+
struct pg_tm tm;
3084+
fsec_t fsec;
30873085

3088-
tm = pg_localtime(&now, tzp);
3089-
tz = -tm->tm_gmtoff;
3086+
if (timestamp2tm(now, &tz, &tm, &fsec, NULL, tzp) != 0)
3087+
ereport(ERROR,
3088+
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3089+
errmsg("timestamp out of range")));
30903090
}
30913091
else
30923092
{

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 202109032
56+
#define CATALOG_VERSION_NO 202109061
5757

5858
#endif

src/include/catalog/pg_proc.dat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5953,7 +5953,7 @@
59535953
proname => 'timestamp_larger', prorettype => 'timestamp',
59545954
proargtypes => 'timestamp timestamp', prosrc => 'timestamp_larger' },
59555955
{ oid => '2037', descr => 'adjust time with time zone to new zone',
5956-
proname => 'timezone', provolatile => 'v', prorettype => 'timetz',
5956+
proname => 'timezone', provolatile => 's', prorettype => 'timetz',
59575957
proargtypes => 'text timetz', prosrc => 'timetz_zone' },
59585958
{ oid => '2038', descr => 'adjust time with time zone to new zone',
59595959
proname => 'timezone', prorettype => 'timetz',

0 commit comments

Comments
 (0)