@@ -426,7 +426,10 @@ typedef struct
426
426
j ,
427
427
us ,
428
428
yysz , /* is it YY or YYYY ? */
429
- clock ; /* 12 or 24 hour clock? */
429
+ clock , /* 12 or 24 hour clock? */
430
+ tzsign ,
431
+ tzh ,
432
+ tzm ;
430
433
} TmFromChar ;
431
434
432
435
#define ZERO_tmfc (_X ) memset(_X, 0, sizeof(TmFromChar))
@@ -472,6 +475,7 @@ do { \
472
475
(_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
473
476
(_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
474
477
(_X)->tm_mday = (_X)->tm_mon = 1; \
478
+ (_X)->tm_zone = NULL; \
475
479
} while(0)
476
480
477
481
#define ZERO_tmtc (_X ) \
@@ -611,6 +615,8 @@ typedef enum
611
615
DCH_RM ,
612
616
DCH_SSSS ,
613
617
DCH_SS ,
618
+ DCH_TZH ,
619
+ DCH_TZM ,
614
620
DCH_TZ ,
615
621
DCH_US ,
616
622
DCH_WW ,
@@ -758,7 +764,9 @@ static const KeyWord DCH_keywords[] = {
758
764
{"RM" , 2 , DCH_RM , FALSE, FROM_CHAR_DATE_GREGORIAN }, /* R */
759
765
{"SSSS" , 4 , DCH_SSSS , TRUE, FROM_CHAR_DATE_NONE }, /* S */
760
766
{"SS" , 2 , DCH_SS , TRUE, FROM_CHAR_DATE_NONE },
761
- {"TZ" , 2 , DCH_TZ , FALSE, FROM_CHAR_DATE_NONE }, /* T */
767
+ {"TZH" , 3 , DCH_TZH , FALSE, FROM_CHAR_DATE_NONE }, /* T */
768
+ {"TZM" , 3 , DCH_TZM , TRUE, FROM_CHAR_DATE_NONE },
769
+ {"TZ" , 2 , DCH_TZ , FALSE, FROM_CHAR_DATE_NONE },
762
770
{"US" , 2 , DCH_US , TRUE, FROM_CHAR_DATE_NONE }, /* U */
763
771
{"WW" , 2 , DCH_WW , TRUE, FROM_CHAR_DATE_GREGORIAN }, /* W */
764
772
{"W" , 1 , DCH_W , TRUE, FROM_CHAR_DATE_GREGORIAN },
@@ -881,7 +889,7 @@ static const int DCH_index[KeyWord_INDEX_SIZE] = {
881
889
-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 ,
882
890
-1 , -1 , -1 , -1 , -1 , DCH_A_D , DCH_B_C , DCH_CC , DCH_DAY , -1 ,
883
891
DCH_FX , -1 , DCH_HH24 , DCH_IDDD , DCH_J , -1 , -1 , DCH_MI , -1 , DCH_OF ,
884
- DCH_P_M , DCH_Q , DCH_RM , DCH_SSSS , DCH_TZ , DCH_US , -1 , DCH_WW , -1 , DCH_Y_YYY ,
892
+ DCH_P_M , DCH_Q , DCH_RM , DCH_SSSS , DCH_TZH , DCH_US , -1 , DCH_WW , -1 , DCH_Y_YYY ,
885
893
-1 , -1 , -1 , -1 , -1 , -1 , -1 , DCH_a_d , DCH_b_c , DCH_cc ,
886
894
DCH_day , -1 , DCH_fx , -1 , DCH_hh24 , DCH_iddd , DCH_j , -1 , -1 , DCH_mi ,
887
895
-1 , -1 , DCH_p_m , DCH_q , DCH_rm , DCH_ssss , DCH_tz , DCH_us , -1 , DCH_ww ,
@@ -2529,6 +2537,13 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
2529
2537
s += strlen (s );
2530
2538
}
2531
2539
break ;
2540
+ case DCH_TZH :
2541
+ case DCH_TZM :
2542
+ ereport (ERROR ,
2543
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2544
+ errmsg ("formatting field \"%s\" is only supported in "
2545
+ "to_timestamp" , n -> key -> name )));
2546
+ break ;
2532
2547
case DCH_OF :
2533
2548
INVALID_FOR_INTERVAL ;
2534
2549
sprintf (s , "%c%0*d" ,
@@ -3080,6 +3095,19 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
3080
3095
errmsg ("formatting field \"%s\" is only supported in to_char" ,
3081
3096
n -> key -> name )));
3082
3097
break ;
3098
+ case DCH_TZH :
3099
+ out -> tzsign = * s == '-' ? -1 : +1 ;
3100
+
3101
+ if (* s == '+' || * s == '-' || * s == ' ' )
3102
+ s ++ ;
3103
+
3104
+ from_char_parse_int_len (& out -> tzh , & s , 2 , n );
3105
+ break ;
3106
+ case DCH_TZM :
3107
+ if (!out -> tzsign )
3108
+ out -> tzsign = +1 ;
3109
+ from_char_parse_int_len (& out -> tzm , & s , 2 , n );
3110
+ break ;
3083
3111
case DCH_A_D :
3084
3112
case DCH_B_C :
3085
3113
case DCH_a_d :
@@ -3545,8 +3573,15 @@ to_timestamp(PG_FUNCTION_ARGS)
3545
3573
fsec_t fsec ;
3546
3574
3547
3575
do_to_timestamp (date_txt , fmt , & tm , & fsec );
3576
+ if (tm .tm_zone )
3577
+ {
3578
+ int dterr = DecodeTimezone ((char * ) tm .tm_zone , & tz );
3548
3579
3549
- tz = DetermineTimeZoneOffset (& tm , session_timezone );
3580
+ if (dterr )
3581
+ DateTimeParseError (dterr , text_to_cstring (date_txt ), "timestamptz" );
3582
+ }
3583
+ else
3584
+ tz = DetermineTimeZoneOffset (& tm , session_timezone );
3550
3585
3551
3586
if (tm2timestamp (& tm , fsec , & tz , & result ) != 0 )
3552
3587
ereport (ERROR ,
@@ -3868,6 +3903,22 @@ do_to_timestamp(text *date_txt, text *fmt,
3868
3903
* fsec < INT64CONST (0 ) || * fsec >= USECS_PER_SEC )
3869
3904
DateTimeParseError (DTERR_FIELD_OVERFLOW , date_str , "timestamp" );
3870
3905
3906
+ if (tmfc .tzsign )
3907
+ {
3908
+ char * tz ;
3909
+
3910
+ if (tmfc .tzh < 0 || tmfc .tzh > MAX_TZDISP_HOUR ||
3911
+ tmfc .tzm < 0 || tmfc .tzm >= MINS_PER_HOUR )
3912
+ DateTimeParseError (DTERR_TZDISP_OVERFLOW , date_str , "timestamp" );
3913
+
3914
+ tz = palloc (7 );
3915
+
3916
+ snprintf (tz , 7 , "%c%02d:%02d" ,
3917
+ tmfc .tzsign > 0 ? '+' : '-' , tmfc .tzh , tmfc .tzm );
3918
+
3919
+ tm -> tm_zone = tz ;
3920
+ }
3921
+
3871
3922
DEBUG_TM (tm );
3872
3923
3873
3924
pfree (date_str );
0 commit comments