88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.166 2006/03/05 15:58:41 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.167 2006/06/07 22:32:31 momjian Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2222
2323#include "access/xact.h"
2424#include "miscadmin.h"
25+ #include "utils/builtins.h"
2526#include "utils/datetime.h"
2627#include "utils/guc.h"
2728
@@ -36,6 +37,7 @@ static int DecodeTime(char *str, int fmask, int *tmask,
3637struct pg_tm * tm ,fsec_t * fsec );
3738static int DecodeTimezone (char * str ,int * tzp );
3839static int DecodePosixTimezone (char * str ,int * tzp );
40+ static int DecodeZicTimezone (char * str ,int * tzp ,struct pg_tm * tm );
3941static datetkn * datebsearch (char * key ,datetkn * base ,unsignedint nel );
4042static int DecodeDate (char * str ,int fmask ,int * tmask ,struct pg_tm * tm );
4143static void TrimTrailingZeros (char * str );
@@ -888,8 +890,24 @@ ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
888890{
889891char delim = * cp ;
890892
891- ftype [nf ]= DTK_DATE ;
892- APPEND_CHAR (bufp ,bufend ,* cp ++ );
893+ if (* cp == '/' )
894+ {
895+ ftype [nf ]= DTK_TZ ;
896+ /* set the first character of the region to upper case
897+ * again*/
898+ field [nf ][0 ]= pg_toupper ((unsignedchar )field [nf ][0 ]);
899+ /* we have seen "Region/" of a POSIX timezone, continue to
900+ * read the City part */
901+ do {
902+ APPEND_CHAR (bufp ,bufend ,* cp ++ );
903+ /* there is for example America/New_York */
904+ }while (isalpha ((unsignedchar )* cp )|| * cp == '_' );
905+ }
906+ else
907+ {
908+ ftype [nf ]= DTK_DATE ;
909+ APPEND_CHAR (bufp ,bufend ,* cp ++ );
910+ }
893911while (isdigit ((unsignedchar )* cp )|| * cp == delim )
894912APPEND_CHAR (bufp ,bufend ,* cp ++ );
895913}
@@ -980,6 +998,7 @@ DecodeDateTime(char **field, int *ftype, int nf,
980998bool haveTextMonth = FALSE;
981999int is2digits = FALSE;
9821000int bc = FALSE;
1001+ int zicTzFnum = -1 ;
9831002
9841003/*
9851004 * We'll insist on at least all of the date fields, but initialize the
@@ -1127,7 +1146,15 @@ DecodeDateTime(char **field, int *ftype, int nf,
11271146if (tzp == NULL )
11281147return DTERR_BAD_FORMAT ;
11291148
1130- dterr = DecodeTimezone (field [i ],& tz );
1149+ if (strchr (field [i ],'/' )!= NULL )
1150+ {
1151+ /* remember to apply the timezone at the end */
1152+ zicTzFnum = i ;
1153+ tmask = DTK_M (TZ );
1154+ break ;
1155+ }
1156+ else
1157+ dterr = DecodeTimezone (field [i ],& tz );
11311158if (dterr )
11321159return dterr ;
11331160
@@ -1605,6 +1632,19 @@ DecodeDateTime(char **field, int *ftype, int nf,
16051632if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
16061633return DTERR_FIELD_OVERFLOW ;
16071634
1635+ if (zicTzFnum != -1 )
1636+ {
1637+ Datum tsTz ;
1638+ Timestamp timestamp ;
1639+ tm2timestamp (tm ,* fsec ,NULL ,& timestamp );
1640+ tsTz = DirectFunctionCall2 (timestamp_zone ,
1641+ DirectFunctionCall1 (textin ,
1642+ CStringGetDatum (field [zicTzFnum ])),
1643+ TimestampGetDatum (timestamp ));
1644+ timestamp2tm (DatumGetTimestampTz (tsTz ),tzp ,tm ,fsec ,NULL ,NULL );
1645+ fmask &= ~DTK_M (TZ );
1646+ }
1647+
16081648/* timezone not specified? then find local timezone if possible */
16091649if (tzp != NULL && !(fmask & DTK_M (TZ )))
16101650{
@@ -1874,7 +1914,15 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
18741914if (tzp == NULL )
18751915return DTERR_BAD_FORMAT ;
18761916
1877- dterr = DecodeTimezone (field [i ],& tz );
1917+ if (strchr (field [i ],'/' )!= NULL )
1918+ {
1919+ /* a date has to be specified */
1920+ if ((fmask & DTK_DATE_M )!= DTK_DATE_M )
1921+ return DTERR_BAD_FORMAT ;
1922+ dterr = DecodeZicTimezone (field [i ],& tz ,tm );
1923+ }
1924+ else
1925+ dterr = DecodeTimezone (field [i ],& tz );
18781926if (dterr )
18791927return dterr ;
18801928
@@ -2924,6 +2972,19 @@ DecodePosixTimezone(char *str, int *tzp)
29242972return 0 ;
29252973}
29262974
2975+ static int
2976+ DecodeZicTimezone (char * str ,int * tzp ,struct pg_tm * tm )
2977+ {
2978+ struct pg_tz * tz ;
2979+
2980+ tz = pg_tzset (str );
2981+ if (!tz )
2982+ return DTERR_BAD_FORMAT ;
2983+
2984+ * tzp = DetermineTimeZoneOffset (tm ,tz );
2985+
2986+ return 0 ;
2987+ }
29272988
29282989/* DecodeSpecial()
29292990 * Decode text string using lookup table.