@@ -491,11 +491,28 @@ typedef struct
491491
492492/* ----------
493493 * Datetime to char conversion
494+ *
495+ * To support intervals as well as timestamps, we use a custom "tm" struct
496+ * that is almost like struct pg_tm, but has a 64-bit tm_hour field.
497+ * We omit the tm_isdst and tm_zone fields, which are not used here.
494498 * ----------
495499 */
500+ struct fmt_tm
501+ {
502+ int tm_sec ;
503+ int tm_min ;
504+ int64 tm_hour ;
505+ int tm_mday ;
506+ int tm_mon ;
507+ int tm_year ;
508+ int tm_wday ;
509+ int tm_yday ;
510+ long int tm_gmtoff ;
511+ };
512+
496513typedef struct TmToChar
497514{
498- struct pg_tm tm ; /* classic 'tm' struct */
515+ struct fmt_tm tm ; /* almost the classic 'tm' struct */
499516 fsec_t fsec ; /* fractional seconds */
500517 const char * tzn ; /* timezone */
501518} TmToChar ;
@@ -504,12 +521,25 @@ typedef struct TmToChar
504521#define tmtcTzn (_X ) ((_X)->tzn)
505522#define tmtcFsec (_X ) ((_X)->fsec)
506523
524+ /* Note: this is used to copy pg_tm to fmt_tm, so not quite a bitwise copy */
525+ #define COPY_tm (_DST , _SRC ) \
526+ do { \
527+ (_DST)->tm_sec = (_SRC)->tm_sec; \
528+ (_DST)->tm_min = (_SRC)->tm_min; \
529+ (_DST)->tm_hour = (_SRC)->tm_hour; \
530+ (_DST)->tm_mday = (_SRC)->tm_mday; \
531+ (_DST)->tm_mon = (_SRC)->tm_mon; \
532+ (_DST)->tm_year = (_SRC)->tm_year; \
533+ (_DST)->tm_wday = (_SRC)->tm_wday; \
534+ (_DST)->tm_yday = (_SRC)->tm_yday; \
535+ (_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
536+ } while(0)
537+
538+ /* Caution: this is used to zero both pg_tm and fmt_tm structs */
507539#define ZERO_tm (_X ) \
508540do { \
509- (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
510- (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
511- (_X)->tm_mday = (_X)->tm_mon = 1; \
512- (_X)->tm_zone = NULL; \
541+ memset(_X, 0, sizeof(*(_X))); \
542+ (_X)->tm_mday = (_X)->tm_mon = 1; \
513543} while(0)
514544
515545#define ZERO_tmtc (_X ) \
@@ -2649,7 +2679,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26492679{
26502680 FormatNode * n ;
26512681 char * s ;
2652- struct pg_tm * tm = & in -> tm ;
2682+ struct fmt_tm * tm = & in -> tm ;
26532683 int i ;
26542684
26552685 /* cache localized days and months */
@@ -2698,16 +2728,17 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
26982728 * display time as shown on a 12-hour clock, even for
26992729 * intervals
27002730 */
2701- sprintf (s , "%0*d" , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2702- tm -> tm_hour % (HOURS_PER_DAY / 2 ) == 0 ? HOURS_PER_DAY / 2 :
2703- tm -> tm_hour % (HOURS_PER_DAY / 2 ));
2731+ sprintf (s , "%0*lld" , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2732+ tm -> tm_hour % (HOURS_PER_DAY / 2 ) == 0 ?
2733+ (long long ) (HOURS_PER_DAY / 2 ) :
2734+ (long long ) (tm -> tm_hour % (HOURS_PER_DAY / 2 )));
27042735 if (S_THth (n -> suffix ))
27052736 str_numth (s , s , S_TH_TYPE (n -> suffix ));
27062737 s += strlen (s );
27072738 break ;
27082739 case DCH_HH24 :
2709- sprintf (s , "%0*d " , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2710- tm -> tm_hour );
2740+ sprintf (s , "%0*lld " , S_FM (n -> suffix ) ? 0 : (tm -> tm_hour >= 0 ) ? 2 : 3 ,
2741+ ( long long ) tm -> tm_hour );
27112742 if (S_THth (n -> suffix ))
27122743 str_numth (s , s , S_TH_TYPE (n -> suffix ));
27132744 s += strlen (s );
@@ -2755,9 +2786,10 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
27552786 break ;
27562787#undef DCH_to_char_fsec
27572788 case DCH_SSSS :
2758- sprintf (s , "%d" , tm -> tm_hour * SECS_PER_HOUR +
2759- tm -> tm_min * SECS_PER_MINUTE +
2760- tm -> tm_sec );
2789+ sprintf (s , "%lld" ,
2790+ (long long ) (tm -> tm_hour * SECS_PER_HOUR +
2791+ tm -> tm_min * SECS_PER_MINUTE +
2792+ tm -> tm_sec ));
27612793 if (S_THth (n -> suffix ))
27622794 str_numth (s , s , S_TH_TYPE (n -> suffix ));
27632795 s += strlen (s );
@@ -4088,7 +4120,8 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40884120 text * fmt = PG_GETARG_TEXT_PP (1 ),
40894121 * res ;
40904122 TmToChar tmtc ;
4091- struct pg_tm * tm ;
4123+ struct pg_tm tt ;
4124+ struct fmt_tm * tm ;
40924125 int thisdate ;
40934126
40944127 if (VARSIZE_ANY_EXHDR (fmt ) <= 0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4097,10 +4130,11 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40974130 ZERO_tmtc (& tmtc );
40984131 tm = tmtcTm (& tmtc );
40994132
4100- if (timestamp2tm (dt , NULL , tm , & tmtcFsec (& tmtc ), NULL , NULL ) != 0 )
4133+ if (timestamp2tm (dt , NULL , & tt , & tmtcFsec (& tmtc ), NULL , NULL ) != 0 )
41014134 ereport (ERROR ,
41024135 (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
41034136 errmsg ("timestamp out of range" )));
4137+ COPY_tm (tm , & tt );
41044138
41054139 thisdate = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday );
41064140 tm -> tm_wday = (thisdate + 1 ) % 7 ;
@@ -4120,7 +4154,8 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41204154 * res ;
41214155 TmToChar tmtc ;
41224156 int tz ;
4123- struct pg_tm * tm ;
4157+ struct pg_tm tt ;
4158+ struct fmt_tm * tm ;
41244159 int thisdate ;
41254160
41264161 if (VARSIZE_ANY_EXHDR (fmt ) <= 0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4129,10 +4164,11 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41294164 ZERO_tmtc (& tmtc );
41304165 tm = tmtcTm (& tmtc );
41314166
4132- if (timestamp2tm (dt , & tz , tm , & tmtcFsec (& tmtc ), & tmtcTzn (& tmtc ), NULL ) != 0 )
4167+ if (timestamp2tm (dt , & tz , & tt , & tmtcFsec (& tmtc ), & tmtcTzn (& tmtc ), NULL ) != 0 )
41334168 ereport (ERROR ,
41344169 (errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
41354170 errmsg ("timestamp out of range" )));
4171+ COPY_tm (tm , & tt );
41364172
41374173 thisdate = date2j (tm -> tm_year , tm -> tm_mon , tm -> tm_mday );
41384174 tm -> tm_wday = (thisdate + 1 ) % 7 ;
@@ -4156,16 +4192,24 @@ interval_to_char(PG_FUNCTION_ARGS)
41564192 text * fmt = PG_GETARG_TEXT_PP (1 ),
41574193 * res ;
41584194 TmToChar tmtc ;
4159- struct pg_tm * tm ;
4195+ struct fmt_tm * tm ;
4196+ struct pg_itm tt ,
4197+ * itm = & tt ;
41604198
41614199 if (VARSIZE_ANY_EXHDR (fmt ) <= 0 )
41624200 PG_RETURN_NULL ();
41634201
41644202 ZERO_tmtc (& tmtc );
41654203 tm = tmtcTm (& tmtc );
41664204
4167- if (interval2tm (* it , tm , & tmtcFsec (& tmtc )) != 0 )
4168- PG_RETURN_NULL ();
4205+ interval2itm (* it , itm );
4206+ tmtc .fsec = itm -> tm_usec ;
4207+ tm -> tm_sec = itm -> tm_sec ;
4208+ tm -> tm_min = itm -> tm_min ;
4209+ tm -> tm_hour = itm -> tm_hour ;
4210+ tm -> tm_mday = itm -> tm_mday ;
4211+ tm -> tm_mon = itm -> tm_mon ;
4212+ tm -> tm_year = itm -> tm_year ;
41694213
41704214 /* wday is meaningless, yday approximates the total span in days */
41714215 tm -> tm_yday = (tm -> tm_year * MONTHS_PER_YEAR + tm -> tm_mon ) * DAYS_PER_MONTH + tm -> tm_mday ;
0 commit comments