diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 2cc9770f65..4b3c1bca19 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,4 +1,4 @@ - + Data Types @@ -1356,8 +1356,8 @@ SELECT b, char_length(b) FROM test2; time [ (p) ] with time zone 12 bytes times of day only, with time zone - 00:00:00+1359 - 24:00:00-1359 + 00:00:00+1459 + 24:00:00-1459 1 microsecond / 14 digits @@ -1594,7 +1594,8 @@ SELECT b, char_length(b) FROM test2; and .) If a time zone is specified in the input for time without time zone, it is silently ignored. You can also specify a date but it will - be ignored, except when you use a full time zone name like + be ignored, except when you use a time zone name that involves a + daylight-savings rule, such as America/New_York. In this case specifying the date is required in order to determine whether standard or daylight-savings time applies. The appropriate time zone offset is recorded in the @@ -1747,12 +1748,7 @@ SELECT b, char_length(b) FROM test2; are valid values, which follow the ISO 8601 - standard. You can also specify the full time zone name as in - -1999-01-08 04:05:06 America/New_York - - - In addition, the wide-spread format + standard. In addition, the wide-spread format January 8 04:05:06 1999 PST @@ -2210,12 +2206,7 @@ January 8 04:05:06 1999 PST There is a conceptual and practical difference between the abbreviations and the full names: abbreviations always represent a fixed offset from UTC, whereas most of the full names imply a local daylight-savings time - rule and so have two possible UTC offsets. That's why you always have to - specify a date if you want to use full time zone names in timetz - values. This is also the reason why you should set to a full time zone name: this way, - PostgreSQL - will always know the correct UTC offset for your region. + rule and so have two possible UTC offsets. diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index cfb29dce56..f72d1c6b40 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.173 2006/10/17 21:03:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.174 2006/10/18 16:43:13 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1199,6 +1199,18 @@ DecodeDateTime(char **field, int *ftype, int nf, ptype = val; break; + case UNKNOWN_FIELD: + /* + * Before giving up and declaring error, check to see + * if it is an all-alpha timezone name. + */ + namedTz = pg_tzset(field[i]); + if (!namedTz) + return DTERR_BAD_FORMAT; + /* we'll apply the zone setting below */ + tmask = DTK_M(TZ); + break; + default: return DTERR_BAD_FORMAT; } @@ -1911,6 +1923,18 @@ DecodeTimeOnly(char **field, int *ftype, int nf, ptype = val; break; + case UNKNOWN_FIELD: + /* + * Before giving up and declaring error, check to see + * if it is an all-alpha timezone name. + */ + namedTz = pg_tzset(field[i]); + if (!namedTz) + return DTERR_BAD_FORMAT; + /* we'll apply the zone setting below */ + tmask = DTK_M(TZ); + break; + default: return DTERR_BAD_FORMAT; } @@ -1952,18 +1976,28 @@ DecodeTimeOnly(char **field, int *ftype, int nf, /* * If we had a full timezone spec, compute the offset (we could not - * do it before, because we need the date to resolve DST status). + * do it before, because we may need the date to resolve DST status). */ if (namedTz != NULL) { - /* a date has to be specified */ - if ((fmask & DTK_DATE_M) != DTK_DATE_M) - return DTERR_BAD_FORMAT; + long int gmtoff; + /* daylight savings time modifier disallowed with full TZ */ if (fmask & DTK_M(DTZMOD)) return DTERR_BAD_FORMAT; - *tzp = DetermineTimeZoneOffset(tm, namedTz); + /* if non-DST zone, we do not need to know the date */ + if (pg_get_timezone_offset(namedTz, &gmtoff)) + { + *tzp = -(int) gmtoff; + } + else + { + /* a date has to be specified */ + if ((fmask & DTK_DATE_M) != DTK_DATE_M) + return DTERR_BAD_FORMAT; + *tzp = DetermineTimeZoneOffset(tm, namedTz); + } } /* timezone not specified? then find local timezone if possible */ diff --git a/src/include/pgtime.h b/src/include/pgtime.h index 0e02c9e24b..bbb83b7fd6 100644 --- a/src/include/pgtime.h +++ b/src/include/pgtime.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.13 2006/09/16 20:14:33 tgl Exp $ + * $PostgreSQL: pgsql/src/include/pgtime.h,v 1.14 2006/10/18 16:43:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -55,6 +55,7 @@ extern size_t pg_strftime(char *s, size_t max, const char *format, extern void pg_timezone_initialize(void); extern pg_tz *pg_tzset(const char *tzname); extern bool tz_acceptable(pg_tz *tz); +extern bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff); extern const char *pg_get_timezone_name(pg_tz *tz); extern pg_tzenum *pg_tzenumerate_start(void); diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h index 56f018b6cc..60a7c159a9 100644 --- a/src/include/utils/datetime.h +++ b/src/include/utils/datetime.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.61 2006/09/16 20:14:33 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/datetime.h,v 1.62 2006/10/18 16:43:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -176,7 +176,7 @@ #define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) #define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) -#define MAXDATELEN 51 /* maximum possible length of an input date +#define MAXDATELEN 63 /* maximum possible length of an input date * string (not counting tr. null) */ #define MAXDATEFIELDS 25 /* maximum possible number of fields in a date * string */ diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c index f5c6c0db8d..fca5ebac64 100644 --- a/src/timezone/localtime.c +++ b/src/timezone/localtime.c @@ -3,7 +3,7 @@ * 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). * * IDENTIFICATION - * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.15 2006/10/16 19:58:26 tgl Exp $ + * $PostgreSQL: pgsql/src/timezone/localtime.c,v 1.16 2006/10/18 16:43:14 tgl Exp $ */ /* @@ -1066,6 +1066,31 @@ pg_next_dst_boundary(const pg_time_t *timep, return 1; } +/* + * If the given timezone uses only one GMT offset, store that offset + * into *gmtoff and return TRUE, else return FALSE. + */ +bool +pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff) +{ + /* + * The zone could have more than one ttinfo, if it's historically used + * more than one abbreviation. We return TRUE as long as they all have + * the same gmtoff. + */ + const struct state *sp; + int i; + + sp = &tz->state; + for (i = 1; i < sp->typecnt; i++) + { + if (sp->ttis[i].tt_gmtoff != sp->ttis[0].tt_gmtoff) + return false; + } + *gmtoff = sp->ttis[0].tt_gmtoff; + return true; +} + /* * Return the name of the current timezone */