@@ -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+ longint 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 */
499516fsec_t fsec ;/* fractional seconds */
500517const 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{
26502680FormatNode * n ;
26512681char * s ;
2652- struct pg_tm * tm = & in -> tm ;
2682+ struct fmt_tm * tm = & in -> tm ;
26532683int 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 )));
27042735if (S_THth (n -> suffix ))
27052736str_numth (s ,s ,S_TH_TYPE (n -> suffix ));
27062737s += strlen (s );
27072738break ;
27082739case 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 );
27112742if (S_THth (n -> suffix ))
27122743str_numth (s ,s ,S_TH_TYPE (n -> suffix ));
27132744s += strlen (s );
@@ -2755,9 +2786,10 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col
27552786break ;
27562787#undef DCH_to_char_fsec
27572788case 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 ));
27612793if (S_THth (n -> suffix ))
27622794str_numth (s ,s ,S_TH_TYPE (n -> suffix ));
27632795s += strlen (s );
@@ -4088,7 +4120,8 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40884120text * fmt = PG_GETARG_TEXT_PP (1 ),
40894121* res ;
40904122TmToChar tmtc ;
4091- struct pg_tm * tm ;
4123+ struct pg_tm tt ;
4124+ struct fmt_tm * tm ;
40924125int thisdate ;
40934126
40944127if (VARSIZE_ANY_EXHDR (fmt ) <=0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4097,10 +4130,11 @@ timestamp_to_char(PG_FUNCTION_ARGS)
40974130ZERO_tmtc (& tmtc );
40984131tm = 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 )
41014134ereport (ERROR ,
41024135(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
41034136errmsg ("timestamp out of range" )));
4137+ COPY_tm (tm ,& tt );
41044138
41054139thisdate = date2j (tm -> tm_year ,tm -> tm_mon ,tm -> tm_mday );
41064140tm -> tm_wday = (thisdate + 1 ) %7 ;
@@ -4120,7 +4154,8 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41204154* res ;
41214155TmToChar tmtc ;
41224156int tz ;
4123- struct pg_tm * tm ;
4157+ struct pg_tm tt ;
4158+ struct fmt_tm * tm ;
41244159int thisdate ;
41254160
41264161if (VARSIZE_ANY_EXHDR (fmt ) <=0 || TIMESTAMP_NOT_FINITE (dt ))
@@ -4129,10 +4164,11 @@ timestamptz_to_char(PG_FUNCTION_ARGS)
41294164ZERO_tmtc (& tmtc );
41304165tm = 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 )
41334168ereport (ERROR ,
41344169(errcode (ERRCODE_DATETIME_VALUE_OUT_OF_RANGE ),
41354170errmsg ("timestamp out of range" )));
4171+ COPY_tm (tm ,& tt );
41364172
41374173thisdate = date2j (tm -> tm_year ,tm -> tm_mon ,tm -> tm_mday );
41384174tm -> tm_wday = (thisdate + 1 ) %7 ;
@@ -4156,16 +4192,24 @@ interval_to_char(PG_FUNCTION_ARGS)
41564192text * fmt = PG_GETARG_TEXT_PP (1 ),
41574193* res ;
41584194TmToChar tmtc ;
4159- struct pg_tm * tm ;
4195+ struct fmt_tm * tm ;
4196+ struct pg_itm tt ,
4197+ * itm = & tt ;
41604198
41614199if (VARSIZE_ANY_EXHDR (fmt ) <=0 )
41624200PG_RETURN_NULL ();
41634201
41644202ZERO_tmtc (& tmtc );
41654203tm = 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 */
41714215tm -> tm_yday = (tm -> tm_year * MONTHS_PER_YEAR + tm -> tm_mon )* DAYS_PER_MONTH + tm -> tm_mday ;