@@ -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 ,
@@ -2535,6 +2543,13 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
2535
2543
s += strlen (s );
2536
2544
}
2537
2545
break ;
2546
+ case DCH_TZH :
2547
+ case DCH_TZM :
2548
+ ereport (ERROR ,
2549
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
2550
+ errmsg ("formatting field \"%s\" is only supported in "
2551
+ "to_timestamp" , n -> key -> name )));
2552
+ break ;
2538
2553
case DCH_OF :
2539
2554
INVALID_FOR_INTERVAL ;
2540
2555
sprintf (s , "%c%0*d" ,
@@ -3086,6 +3101,19 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
3086
3101
errmsg ("formatting field \"%s\" is only supported in to_char" ,
3087
3102
n -> key -> name )));
3088
3103
break ;
3104
+ case DCH_TZH :
3105
+ out -> tzsign = * s == '-' ? -1 : +1 ;
3106
+
3107
+ if (* s == '+' || * s == '-' || * s == ' ' )
3108
+ s ++ ;
3109
+
3110
+ from_char_parse_int_len (& out -> tzh , & s , 2 , n );
3111
+ break ;
3112
+ case DCH_TZM :
3113
+ if (!out -> tzsign )
3114
+ out -> tzsign = +1 ;
3115
+ from_char_parse_int_len (& out -> tzm , & s , 2 , n );
3116
+ break ;
3089
3117
case DCH_A_D :
3090
3118
case DCH_B_C :
3091
3119
case DCH_a_d :
@@ -3551,8 +3579,15 @@ to_timestamp(PG_FUNCTION_ARGS)
3551
3579
fsec_t fsec ;
3552
3580
3553
3581
do_to_timestamp (date_txt , fmt , & tm , & fsec );
3582
+ if (tm .tm_zone )
3583
+ {
3584
+ int dterr = DecodeTimezone ((char * ) tm .tm_zone , & tz );
3554
3585
3555
- tz = DetermineTimeZoneOffset (& tm , session_timezone );
3586
+ if (dterr )
3587
+ DateTimeParseError (dterr , text_to_cstring (date_txt ), "timestamptz" );
3588
+ }
3589
+ else
3590
+ tz = DetermineTimeZoneOffset (& tm , session_timezone );
3556
3591
3557
3592
if (tm2timestamp (& tm , fsec , & tz , & result ) != 0 )
3558
3593
ereport (ERROR ,
@@ -3874,6 +3909,22 @@ do_to_timestamp(text *date_txt, text *fmt,
3874
3909
* fsec < INT64CONST (0 ) || * fsec >= USECS_PER_SEC )
3875
3910
DateTimeParseError (DTERR_FIELD_OVERFLOW , date_str , "timestamp" );
3876
3911
3912
+ if (tmfc .tzsign )
3913
+ {
3914
+ char * tz ;
3915
+
3916
+ if (tmfc .tzh < 0 || tmfc .tzh > MAX_TZDISP_HOUR ||
3917
+ tmfc .tzm < 0 || tmfc .tzm >= MINS_PER_HOUR )
3918
+ DateTimeParseError (DTERR_TZDISP_OVERFLOW , date_str , "timestamp" );
3919
+
3920
+ tz = palloc (7 );
3921
+
3922
+ snprintf (tz , 7 , "%c%02d:%02d" ,
3923
+ tmfc .tzsign > 0 ? '+' : '-' , tmfc .tzh , tmfc .tzm );
3924
+
3925
+ tm -> tm_zone = tz ;
3926
+ }
3927
+
3877
3928
DEBUG_TM (tm );
3878
3929
3879
3930
pfree (date_str );
0 commit comments