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

Commit 0851a6f

Browse files
committed
This patch makes it possible to use the full set of timezones when doing
"AT TIME ZONE", and not just the shorlist previously available. For example: SELECT CURRENT_TIMESTAMP AT TIME ZONE 'Europe/London'; works fine now. It will also obey whatever DST rules were in effect at just that date, which the previous implementation did not. It also supports the AT TIME ZONE on the timetz datatype. The whole handling of DST is a bit bogus there, so I chose to make it use whatever DST rules are in effect at the time of executig the query. not sure if anybody is actuallyi *using* timetz though, it seems pretty unpredictable just because of this... Magnus Hagander
1 parent 5955945 commit 0851a6f

File tree

9 files changed

+142
-126
lines changed

9 files changed

+142
-126
lines changed

doc/src/sgml/datetime.sgml

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.46 2005/06/15 00:34:08 momjian Exp $
33
-->
44

55
<appendix id="datetime-appendix">
@@ -990,7 +990,9 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp
990990
<para>
991991
<xref linkend="datetime-timezone-set-table"> shows the time zone
992992
names recognized by <productname>PostgreSQL</productname> as valid
993-
settings for the <xref linkend="guc-timezone"> parameter. Note that
993+
settings for the <xref linkend="guc-timezone"> parameter, and as
994+
parameters to the <literal>AT TIME ZONE function</> (see
995+
<xref linkend="functions-datetime-zoneconvert">). Note that
994996
these names are conceptually as well as practically different from
995997
the names shown in <xref linkend="datetime-timezone-input-table">:
996998
most of these names imply a local daylight-savings time rule, whereas
@@ -1004,7 +1006,7 @@ $PostgreSQL: pgsql/doc/src/sgml/datetime.sgml,v 2.45 2005/01/09 18:58:10 tgl Exp
10041006
</para>
10051007

10061008
<table id="datetime-timezone-set-table">
1007-
<title>Time Zone Names for Setting <varname>timezone</></title>
1009+
<title>Time Zone Names for Setting <varname>timezone</> and <literal>AT TIME ZONE</></title>
10081010
<tgroup cols="1">
10091011
<thead>
10101012
<row>

doc/src/sgml/func.sgml

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.256 2005/06/14 23:47:39 momjian Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.257 2005/06/15 00:34:08 momjian Exp $
33
PostgreSQL documentation
44
-->
55

@@ -5679,10 +5679,7 @@ SELECT date_trunc('year', TIMESTAMP '2001-02-16 20:38:40');
56795679
specified either as a text string (e.g., <literal>'PST'</literal>)
56805680
or as an interval (e.g., <literal>INTERVAL '-08:00'</literal>).
56815681
In the text case, the available zone names are those shown in
5682-
<xref linkend="datetime-timezone-input-table">. (It would be useful
5683-
to support the more general names shown in
5684-
<xref linkend="datetime-timezone-set-table">, but this is not yet
5685-
implemented.)
5682+
<xref linkend="datetime-timezone-set-table">.
56865683
</para>
56875684

56885685
<para>

src/backend/utils/adt/date.c

+48-40
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.109 2005/05/26 02:04:13 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.110 2005/06/15 00:34:08 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -18,6 +18,7 @@
1818
#include <ctype.h>
1919
#include <limits.h>
2020
#include <float.h>
21+
#include <time.h>
2122

2223
#include "access/hash.h"
2324
#include "libpq/pqformat.h"
@@ -724,7 +725,7 @@ timestamp_date(PG_FUNCTION_ARGS)
724725
if (TIMESTAMP_NOT_FINITE(timestamp))
725726
PG_RETURN_NULL();
726727

727-
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
728+
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
728729
ereport(ERROR,
729730
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
730731
errmsg("timestamp out of range")));
@@ -767,7 +768,7 @@ timestamptz_date(PG_FUNCTION_ARGS)
767768
if (TIMESTAMP_NOT_FINITE(timestamp))
768769
PG_RETURN_NULL();
769770

770-
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
771+
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
771772
ereport(ERROR,
772773
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
773774
errmsg("timestamp out of range")));
@@ -1327,7 +1328,7 @@ timestamp_time(PG_FUNCTION_ARGS)
13271328
if (TIMESTAMP_NOT_FINITE(timestamp))
13281329
PG_RETURN_NULL();
13291330

1330-
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) !=0)
1331+
if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) !=0)
13311332
ereport(ERROR,
13321333
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
13331334
errmsg("timestamp out of range")));
@@ -1364,7 +1365,7 @@ timestamptz_time(PG_FUNCTION_ARGS)
13641365
if (TIMESTAMP_NOT_FINITE(timestamp))
13651366
PG_RETURN_NULL();
13661367

1367-
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
1368+
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
13681369
ereport(ERROR,
13691370
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
13701371
errmsg("timestamp out of range")));
@@ -2247,7 +2248,7 @@ timestamptz_timetz(PG_FUNCTION_ARGS)
22472248
if (TIMESTAMP_NOT_FINITE(timestamp))
22482249
PG_RETURN_NULL();
22492250

2250-
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn) !=0)
2251+
if (timestamp2tm(timestamp, &tz, tm, &fsec, &tzn, NULL) !=0)
22512252
ereport(ERROR,
22522253
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
22532254
errmsg("timestamp out of range")));
@@ -2463,53 +2464,60 @@ timetz_part(PG_FUNCTION_ARGS)
24632464

24642465
/* timetz_zone()
24652466
* Encode time with time zone type with specified time zone.
2467+
* Applies DST rules as of the current date.
24662468
*/
24672469
Datum
24682470
timetz_zone(PG_FUNCTION_ARGS)
24692471
{
24702472
text *zone = PG_GETARG_TEXT_P(0);
2471-
TimeTzADT *time = PG_GETARG_TIMETZADT_P(1);
2473+
TimeTzADT *t = PG_GETARG_TIMETZADT_P(1);
24722474
TimeTzADT *result;
24732475
int tz;
2474-
int type,
2475-
val;
2476-
char *lowzone;
2477-
2478-
lowzone = downcase_truncate_identifier(VARDATA(zone),
2479-
VARSIZE(zone) - VARHDRSZ,
2480-
false);
2481-
2482-
type = DecodeSpecial(0, lowzone, &val);
2476+
char tzname[TZ_STRLEN_MAX];
2477+
int len;
2478+
pg_tz *tzp;
2479+
struct pg_tm *tm;
2480+
pg_time_t now;
2481+
2482+
/* Find the specified timezone */
2483+
len = (VARSIZE(zone)-VARHDRSZ>TZ_STRLEN_MAX)?TZ_STRLEN_MAX:(VARSIZE(zone)-VARHDRSZ);
2484+
memcpy(tzname,VARDATA(zone),len);
2485+
tzname[len]=0;
2486+
tzp = pg_tzset(tzname);
2487+
if (!tzp) {
2488+
ereport(ERROR,
2489+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2490+
errmsg("time zone \"%s\" not recognized", tzname)));
2491+
PG_RETURN_NULL();
2492+
}
24832493

2484-
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
2494+
/* Get the offset-from-GMT that is valid today for the selected zone */
2495+
if ((now = time(NULL)) < 0 ||
2496+
(tm = pg_localtime(&now, tzp)) == NULL) {
2497+
ereport(ERROR,
2498+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2499+
errmsg("could not determine current time")));
2500+
PG_RETURN_NULL();
2501+
}
24852502

2486-
if (type == TZ || type == DTZ)
2487-
{
2488-
tz = val * 60;
2503+
result = (TimeTzADT *)palloc(sizeof(TimeTzADT));
2504+
2505+
tz = -tm->tm_gmtoff;
24892506
#ifdef HAVE_INT64_TIMESTAMP
2490-
result->time = time->time + (time->zone - tz) * USECS_PER_SEC;
2491-
while (result->time < INT64CONST(0))
2492-
result->time += USECS_PER_DAY;
2493-
while (result->time >= USECS_PER_DAY)
2494-
result->time -= USECS_PER_DAY;
2507+
result->time = t->time + (t->zone - tz) * USECS_PER_SEC;
2508+
while (result->time < INT64CONST(0))
2509+
result->time += USECS_PER_DAY;
2510+
while (result->time >= USECS_PER_DAY)
2511+
result->time -= USECS_PER_DAY;
24952512
#else
2496-
result->time = time->time + (time->zone - tz);
2497-
while (result->time < 0)
2498-
result->time += SECS_PER_DAY;
2499-
while (result->time >= SECS_PER_DAY)
2500-
result->time -= SECS_PER_DAY;
2513+
result->time = t->time + (t->zone - tz);
2514+
while (result->time < 0)
2515+
result->time += SECS_PER_DAY;
2516+
while (result->time >= SECS_PER_DAY)
2517+
result->time -= SECS_PER_DAY;
25012518
#endif
25022519

2503-
result->zone = tz;
2504-
}
2505-
else
2506-
{
2507-
ereport(ERROR,
2508-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2509-
errmsg("time zone \"%s\" not recognized", lowzone)));
2510-
2511-
PG_RETURN_NULL();
2512-
}
2520+
result->zone = tz;
25132521

25142522
PG_RETURN_TIMETZADT_P(result);
25152523
} /* timetz_zone() */

src/backend/utils/adt/formatting.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* -----------------------------------------------------------------------
22
* formatting.c
33
*
4-
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.87 2005/05/25 21:40:40 momjian Exp $
4+
* $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.88 2005/06/15 00:34:08 momjian Exp $
55
*
66
*
77
* Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
@@ -2910,7 +2910,7 @@ timestamp_to_char(PG_FUNCTION_ARGS)
29102910

29112911
ZERO_tmtc(&tmtc);
29122912

2913-
if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL) != 0)
2913+
if (timestamp2tm(dt, NULL, tmtcTm(&tmtc), &tmtcFsec(&tmtc), NULL, NULL) != 0)
29142914
ereport(ERROR,
29152915
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
29162916
errmsg("timestamp out of range")));
@@ -2935,7 +2935,7 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
29352935

29362936
ZERO_tmtc(&tmtc);
29372937

2938-
if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc)) != 0)
2938+
if (timestamp2tm(dt, &tz, tmtcTm(&tmtc), &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
29392939
ereport(ERROR,
29402940
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
29412941
errmsg("timestamp out of range")));

src/backend/utils/adt/nabstime.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.132 2005/05/26 02:04:13 neilc Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/adt/nabstime.c,v 1.133 2005/06/15 00:34:08 momjian Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -556,7 +556,7 @@ timestamp_abstime(PG_FUNCTION_ARGS)
556556
result = NOSTART_ABSTIME;
557557
else if (TIMESTAMP_IS_NOEND(timestamp))
558558
result = NOEND_ABSTIME;
559-
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
559+
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
560560
{
561561
tz = DetermineLocalTimeZone(tm);
562562
result = tm2abstime(tm, tz);
@@ -632,7 +632,7 @@ timestamptz_abstime(PG_FUNCTION_ARGS)
632632
result = NOSTART_ABSTIME;
633633
else if (TIMESTAMP_IS_NOEND(timestamp))
634634
result = NOEND_ABSTIME;
635-
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL) == 0)
635+
else if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
636636
result = tm2abstime(tm, 0);
637637
else
638638
{

0 commit comments

Comments
 (0)