11/* -----------------------------------------------------------------------
22 * formatting.c
33 *
4- * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.23 2000/10/29 13:17:34 petere Exp $
4+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/formatting.c,v 1.24 2000/11/25 05:00:29 momjian Exp $
55 *
66 *
77 * Portions Copyright (c) 1999-2000, PostgreSQL, Inc
@@ -127,6 +127,7 @@ typedef struct
127127 int len , /* keyword length */
128128 (* action ) (),
129129 id ; /* keyword id */
130+ bool isdigit ; /* is expected output/input digit */
130131} KeyWord ;
131132
132133typedef struct
@@ -344,14 +345,16 @@ static int NUMCounter = 0;
344345 * ----------
345346 */
346347typedef struct {
347- int hh , am , pm , mi , ss , ssss , d , dd , ddd , mm , yyyy , bc , iw , ww , w , cc , q , j ;
348+ int hh , am , pm , mi , ss , ssss , d , dd , ddd , mm , yyyy , yyy , yy , y ,
349+ bc , iw , ww , w , cc , q , j ;
348350} TmFromChar ;
349351
350352#define ZERO_tmfc ( _X ) \
351353 do { \
352354 (_X)->hh= (_X)->am= (_X)->pm= (_X)->mi= (_X)->ss= (_X)->ssss= \
353- (_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->bc= \
354- (_X)->iw= (_X)->ww= (_X)->w= (_X)->cc= (_X)->q= (_X)->j= 0; \
355+ (_X)->d= (_X)->dd= (_X)->ddd= (_X)->mm= (_X)->yyyy= (_X)->yyy= \
356+ (_X)->yy= (_X)->y= (_X)->bc= (_X)->iw= (_X)->ww= (_X)->w= \
357+ (_X)->cc= (_X)->q= (_X)->j= 0; \
355358 } while(0)
356359
357360#ifdef DEBUG_TO_FROM_CHAR
@@ -453,7 +456,7 @@ static KeySuffix DCH_suff[] = {
453456 * it is not good.
454457 *
455458 * (!)
456- * Position for the keyword is simular as position in the enum DCH/NUM_poz
459+ * - Position for the keyword is simular as position in the enum DCH/NUM_poz.
457460 * (!)
458461 *
459462 * For fast search is used the 'int index[]', index is ascii table from position
@@ -598,88 +601,88 @@ typedef enum
598601 * ----------
599602 */
600603static KeyWord DCH_keywords [] = {
601- /* keyword,len,func. type is in Index */
602- {"A.D." , 4 , dch_date , DCH_A_D }, /* A */
603- {"A.M." , 4 , dch_time , DCH_A_M },
604- {"AD" , 2 , dch_date , DCH_AD },
605- {"AM" , 2 , dch_time , DCH_AM },
606- {"B.C." , 4 , dch_date , DCH_B_C }, /* B */
607- {"BC" , 2 , dch_date , DCH_BC },
608- {"CC" , 2 , dch_date , DCH_CC }, /* C */
609- {"DAY" , 3 , dch_date , DCH_DAY }, /* D */
610- {"DDD" , 3 , dch_date , DCH_DDD },
611- {"DD" , 2 , dch_date , DCH_DD },
612- {"DY" , 2 , dch_date , DCH_DY },
613- {"Day" , 3 , dch_date , DCH_Day },
614- {"Dy" , 2 , dch_date , DCH_Dy },
615- {"D" , 1 , dch_date , DCH_D },
616- {"FX" , 2 , dch_global , DCH_FX }, /* F */
617- {"HH24" , 4 , dch_time , DCH_HH24 }, /* H */
618- {"HH12" , 4 , dch_time , DCH_HH12 },
619- {"HH" , 2 , dch_time , DCH_HH },
620- {"IW" , 2 , dch_date , DCH_IW }, /* I */
621- {"J" , 1 , dch_date , DCH_J }, /* J */
622- {"MI" , 2 , dch_time , DCH_MI },
623- {"MM" , 2 , dch_date , DCH_MM },
624- {"MONTH" , 5 , dch_date , DCH_MONTH },
625- {"MON" , 3 , dch_date , DCH_MON },
626- {"Month" , 5 , dch_date , DCH_Month },
627- {"Mon" , 3 , dch_date , DCH_Mon },
628- {"P.M." , 4 , dch_time , DCH_P_M }, /* P */
629- {"PM" , 2 , dch_time , DCH_PM },
630- {"Q" , 1 , dch_date , DCH_Q }, /* Q */
631- {"RM" , 2 , dch_date , DCH_RM }, /* R */
632- {"SSSS" , 4 , dch_time , DCH_SSSS }, /* S */
633- {"SS" , 2 , dch_time , DCH_SS },
634- {"TZ" , 2 , dch_time , DCH_TZ }, /* T */
635- {"WW" , 2 , dch_date , DCH_WW }, /* W */
636- {"W" , 1 , dch_date , DCH_W },
637- {"Y,YYY" , 5 , dch_date , DCH_Y_YYY }, /* Y */
638- {"YYYY" , 4 , dch_date , DCH_YYYY },
639- {"YYY" , 3 , dch_date , DCH_YYY },
640- {"YY" , 2 , dch_date , DCH_YY },
641- {"Y" , 1 , dch_date , DCH_Y },
642- {"a.d." , 4 , dch_date , DCH_a_d }, /* a */
643- {"a.m." , 4 , dch_time , DCH_a_m },
644- {"ad" , 2 , dch_date , DCH_ad },
645- {"am" , 2 , dch_time , DCH_am },
646- {"b.c." , 4 , dch_date , DCH_b_c }, /* b */
647- {"bc" , 2 , dch_date , DCH_bc },
648- {"cc" , 2 , dch_date , DCH_CC }, /* c */
649- {"day" , 3 , dch_date , DCH_day }, /* d */
650- {"ddd" , 3 , dch_date , DCH_DDD },
651- {"dd" , 2 , dch_date , DCH_DD },
652- {"dy" , 2 , dch_date , DCH_dy },
653- {"d" , 1 , dch_date , DCH_D },
654- {"fx" , 2 , dch_global , DCH_FX }, /* f */
655- {"hh24" , 4 , dch_time , DCH_HH24 }, /* h */
656- {"hh12" , 4 , dch_time , DCH_HH12 },
657- {"hh" , 2 , dch_time , DCH_HH },
658- {"iw" , 2 , dch_date , DCH_IW }, /* i */
659- {"j" , 1 , dch_time , DCH_J }, /* j */
660- {"mi" , 2 , dch_time , DCH_MI }, /* m */
661- {"mm" , 2 , dch_date , DCH_MM },
662- {"month" , 5 , dch_date , DCH_month },
663- {"mon" , 3 , dch_date , DCH_mon },
664- {"p.m." , 4 , dch_time , DCH_p_m }, /* p */
665- {"pm" , 2 , dch_time , DCH_pm },
666- {"q" , 1 , dch_date , DCH_Q }, /* q */
667- {"rm" , 2 , dch_date , DCH_rm }, /* r */
668- {"ssss" , 4 , dch_time , DCH_SSSS }, /* s */
669- {"ss" , 2 , dch_time , DCH_SS },
670- {"tz" , 2 , dch_time , DCH_tz }, /* t */
671- {"ww" , 2 , dch_date , DCH_WW }, /* w */
672- {"w" , 1 , dch_date , DCH_W },
673- {"y,yyy" , 5 , dch_date , DCH_Y_YYY }, /* y */
674- {"yyyy" , 4 , dch_date , DCH_YYYY },
675- {"yyy" , 3 , dch_date , DCH_YYY },
676- {"yy" , 2 , dch_date , DCH_YY },
677- {"y" , 1 , dch_date , DCH_Y },
604+ /* keyword, len, func, type, isdigit is in Index */
605+ {"A.D." , 4 , dch_date , DCH_A_D , FALSE }, /* A */
606+ {"A.M." , 4 , dch_time , DCH_A_M , FALSE },
607+ {"AD" , 2 , dch_date , DCH_AD , FALSE },
608+ {"AM" , 2 , dch_time , DCH_AM , FALSE },
609+ {"B.C." , 4 , dch_date , DCH_B_C , FALSE }, /* B */
610+ {"BC" , 2 , dch_date , DCH_BC , FALSE },
611+ {"CC" , 2 , dch_date , DCH_CC , TRUE }, /* C */
612+ {"DAY" , 3 , dch_date , DCH_DAY , FALSE }, /* D */
613+ {"DDD" , 3 , dch_date , DCH_DDD , TRUE },
614+ {"DD" , 2 , dch_date , DCH_DD , TRUE },
615+ {"DY" , 2 , dch_date , DCH_DY , FALSE },
616+ {"Day" , 3 , dch_date , DCH_Day , FALSE },
617+ {"Dy" , 2 , dch_date , DCH_Dy , FALSE },
618+ {"D" , 1 , dch_date , DCH_D , TRUE },
619+ {"FX" , 2 , dch_global , DCH_FX , FALSE }, /* F */
620+ {"HH24" , 4 , dch_time , DCH_HH24 , TRUE}, /* H */
621+ {"HH12" , 4 , dch_time , DCH_HH12 , TRUE },
622+ {"HH" , 2 , dch_time , DCH_HH , TRUE },
623+ {"IW" , 2 , dch_date , DCH_IW , TRUE }, /* I */
624+ {"J" , 1 , dch_date , DCH_J , TRUE }, /* J */
625+ {"MI" , 2 , dch_time , DCH_MI , TRUE },
626+ {"MM" , 2 , dch_date , DCH_MM , TRUE },
627+ {"MONTH" , 5 , dch_date , DCH_MONTH , FALSE },
628+ {"MON" , 3 , dch_date , DCH_MON , FALSE },
629+ {"Month" , 5 , dch_date , DCH_Month , FALSE },
630+ {"Mon" , 3 , dch_date , DCH_Mon , FALSE },
631+ {"P.M." , 4 , dch_time , DCH_P_M , FALSE }, /* P */
632+ {"PM" , 2 , dch_time , DCH_PM , FALSE },
633+ {"Q" , 1 , dch_date , DCH_Q , TRUE }, /* Q */
634+ {"RM" , 2 , dch_date , DCH_RM , FALSE }, /* R */
635+ {"SSSS" , 4 , dch_time , DCH_SSSS , TRUE }, /* S */
636+ {"SS" , 2 , dch_time , DCH_SS , TRUE },
637+ {"TZ" , 2 , dch_time , DCH_TZ , FALSE }, /* T */
638+ {"WW" , 2 , dch_date , DCH_WW , TRUE }, /* W */
639+ {"W" , 1 , dch_date , DCH_W , TRUE },
640+ {"Y,YYY" , 5 , dch_date , DCH_Y_YYY , TRUE }, /* Y */
641+ {"YYYY" , 4 , dch_date , DCH_YYYY , TRUE },
642+ {"YYY" , 3 , dch_date , DCH_YYY , TRUE },
643+ {"YY" , 2 , dch_date , DCH_YY , TRUE },
644+ {"Y" , 1 , dch_date , DCH_Y , TRUE },
645+ {"a.d." , 4 , dch_date , DCH_a_d , FALSE }, /* a */
646+ {"a.m." , 4 , dch_time , DCH_a_m , FALSE },
647+ {"ad" , 2 , dch_date , DCH_ad , FALSE },
648+ {"am" , 2 , dch_time , DCH_am , FALSE },
649+ {"b.c." , 4 , dch_date , DCH_b_c , FALSE }, /* b */
650+ {"bc" , 2 , dch_date , DCH_bc , FALSE },
651+ {"cc" , 2 , dch_date , DCH_CC , TRUE }, /* c */
652+ {"day" , 3 , dch_date , DCH_day , FALSE }, /* d */
653+ {"ddd" , 3 , dch_date , DCH_DDD , TRUE },
654+ {"dd" , 2 , dch_date , DCH_DD , TRUE },
655+ {"dy" , 2 , dch_date , DCH_dy , FALSE },
656+ {"d" , 1 , dch_date , DCH_D , TRUE },
657+ {"fx" , 2 , dch_global , DCH_FX , FALSE }, /* f */
658+ {"hh24" , 4 , dch_time , DCH_HH24 , TRUE}, /* h */
659+ {"hh12" , 4 , dch_time , DCH_HH12 , TRUE },
660+ {"hh" , 2 , dch_time , DCH_HH , TRUE },
661+ {"iw" , 2 , dch_date , DCH_IW , TRUE }, /* i */
662+ {"j" , 1 , dch_time , DCH_J , TRUE }, /* j */
663+ {"mi" , 2 , dch_time , DCH_MI , TRUE }, /* m */
664+ {"mm" , 2 , dch_date , DCH_MM , TRUE },
665+ {"month" , 5 , dch_date , DCH_month , FALSE },
666+ {"mon" , 3 , dch_date , DCH_mon , FALSE },
667+ {"p.m." , 4 , dch_time , DCH_p_m , FALSE }, /* p */
668+ {"pm" , 2 , dch_time , DCH_pm , FALSE },
669+ {"q" , 1 , dch_date , DCH_Q , TRUE }, /* q */
670+ {"rm" , 2 , dch_date , DCH_rm , FALSE }, /* r */
671+ {"ssss" , 4 , dch_time , DCH_SSSS , TRUE }, /* s */
672+ {"ss" , 2 , dch_time , DCH_SS , TRUE },
673+ {"tz" , 2 , dch_time , DCH_tz , FALSE }, /* t */
674+ {"ww" , 2 , dch_date , DCH_WW , TRUE }, /* w */
675+ {"w" , 1 , dch_date , DCH_W , TRUE },
676+ {"y,yyy" , 5 , dch_date , DCH_Y_YYY , TRUE }, /* y */
677+ {"yyyy" , 4 , dch_date , DCH_YYYY , TRUE },
678+ {"yyy" , 3 , dch_date , DCH_YYY , TRUE },
679+ {"yy" , 2 , dch_date , DCH_YY , TRUE },
680+ {"y" , 1 , dch_date , DCH_Y , TRUE },
678681/* last */
679682{NULL , 0 , NULL , 0 }};
680683
681684/* ----------
682- * KeyWords for NUMBER version
685+ * KeyWords for NUMBER version (now, isdigit info is not needful here..)
683686 * ----------
684687 */
685688static KeyWord NUM_keywords [] = {
@@ -1230,7 +1233,7 @@ DCH_processor(FormatNode *node, char *inout, int flag)
12301233 * Skip blank space in FROM_CHAR's input
12311234 * ----------
12321235 */
1233- if (isspace (n -> character ) && IS_FX == 0 )
1236+ if (isspace (n -> character ) && IS_FX == 0 )
12341237 {
12351238 while (* s != '\0' && isspace ((int ) * (s + 1 )))
12361239 ++ s ;
@@ -1526,6 +1529,40 @@ dch_global(int arg, char *inout, int suf, int flag, FormatNode *node)
15261529 return -1 ;
15271530}
15281531
1532+ /* ----------
1533+ * Return TRUE if next format picture is not digit value
1534+ * ----------
1535+ */
1536+ static bool
1537+ is_next_separator (FormatNode * n )
1538+ {
1539+ if (n -> type == NODE_TYPE_END )
1540+ return FALSE;
1541+
1542+ if (n -> type == NODE_TYPE_ACTION && S_THth (n -> suffix ))
1543+ return TRUE;
1544+
1545+ /*
1546+ * Next node
1547+ */
1548+ n ++ ;
1549+
1550+ if (n -> type == NODE_TYPE_END )
1551+ return FALSE;
1552+
1553+ if (n -> type == NODE_TYPE_ACTION )
1554+ {
1555+ if (n -> key -> isdigit )
1556+ return FALSE;
1557+
1558+ return TRUE;
1559+ }
1560+ else if (isdigit (n -> character ))
1561+ return FALSE;
1562+
1563+ return TRUE; /* some non-digit input (separator) */
1564+ }
1565+
15291566#define AMPM_ERROR elog(ERROR, "to_timestamp(): bad AM/PM string")
15301567
15311568/* ----------
@@ -1736,7 +1773,10 @@ dch_time(int arg, char *inout, int suf, int flag, FormatNode *node)
17361773 }
17371774 else if (flag == FROM_CHAR )
17381775 {
1739- sscanf (inout , "%d" , & tmfc -> ssss );
1776+ if (is_next_separator (node ))
1777+ sscanf (inout , "%d" , & tmfc -> ssss );
1778+ else
1779+ sscanf (inout , "%05d" , & tmfc -> ssss );
17401780 return int4len ((int4 ) tmfc -> ssss ) - 1 + SKIP_THth (suf );
17411781 }
17421782 break ;
@@ -2192,7 +2232,11 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
21922232 }
21932233 else if (flag == FROM_CHAR )
21942234 {
2195- sscanf (inout , "%d" , & tmfc -> yyyy );
2235+ if (is_next_separator (node ))
2236+ sscanf (inout , "%d" , & tmfc -> yyyy );
2237+ else
2238+ sscanf (inout , "%04d" , & tmfc -> yyyy );
2239+
21962240 if (!S_FM (suf ) && tmfc -> yyyy <= 9999 && tmfc -> yyyy >= -9999 )
21972241 len = 4 ;
21982242 else
@@ -2217,7 +2261,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
22172261 }
22182262 else if (flag == FROM_CHAR )
22192263 {
2220- sscanf (inout , "%03d" , & tmfc -> yyyy );
2264+ sscanf (inout , "%03d" , & tmfc -> yyy );
22212265 return 2 + SKIP_THth (suf );
22222266 }
22232267 break ;
@@ -2237,7 +2281,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
22372281 }
22382282 else if (flag == FROM_CHAR )
22392283 {
2240- sscanf (inout , "%02d" , & tmfc -> yyyy );
2284+ sscanf (inout , "%02d" , & tmfc -> yy );
22412285 return 1 + SKIP_THth (suf );
22422286 }
22432287 break ;
@@ -2257,7 +2301,7 @@ dch_date(int arg, char *inout, int suf, int flag, FormatNode *node)
22572301 }
22582302 else if (flag == FROM_CHAR )
22592303 {
2260- sscanf (inout , "%1d" , & tmfc -> yyyy );
2304+ sscanf (inout , "%1d" , & tmfc -> y );
22612305 return 0 + SKIP_THth (suf );
22622306 }
22632307 break ;
@@ -2725,15 +2769,55 @@ to_timestamp(PG_FUNCTION_ARGS)
27252769
27262770 if (tmfc -> yyyy )
27272771 tm -> tm_year = tmfc -> yyyy ;
2772+
2773+ else if (tmfc -> y )
2774+ {
2775+ /*
2776+ * 1-digit year:
2777+ * always +2000
2778+ */
2779+ tm -> tm_year = tmfc -> y + 2000 ;
2780+ }
2781+ else if (tmfc -> yy )
2782+ {
2783+ /*
2784+ * 2-digit year:
2785+ * '00' ... '69' = 2000 ... 2069
2786+ * '70' ... '99' = 1970 ... 1999
2787+ */
2788+ tm -> tm_year = tmfc -> yy ;
27282789
2729- if (tmfc -> j )
2730- j2date (tmfc -> j , & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday );
2790+ if (tm -> tm_year < 70 )
2791+ tm -> tm_year += 2000 ;
2792+ else
2793+ tm -> tm_year += 1900 ;
2794+ }
2795+ else if (tmfc -> yyy )
2796+ {
2797+ /*
2798+ * 3-digit year:
2799+ * '100' ... '999' = 1100 ... 1999
2800+ * '000' ... '099' = 2000 ... 2099
2801+ */
2802+ tm -> tm_year = tmfc -> yyy ;
27312803
2732- if (tmfc -> bc && tm -> tm_year > 0 )
2733- tm -> tm_year = - (tm -> tm_year );
2804+ if (tm -> tm_year >= 100 )
2805+ tm -> tm_year += 1000 ;
2806+ else
2807+ tm -> tm_year += 2000 ;
2808+ }
2809+
2810+
2811+ if (tmfc -> bc )
2812+ {
2813+ if (tm -> tm_year > 0 )
2814+ tm -> tm_year = - (tm -> tm_year - 1 );
2815+ else
2816+ elog (ERROR , "Inconsistant use of year %04d and 'BC'" , tm -> tm_year );
2817+ }
27342818
2735- if (tm -> tm_year < 0 )
2736- tm -> tm_year = tm -> tm_year + 1 ;
2819+ if (tmfc -> j )
2820+ j2date ( tmfc -> j , & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday ) ;
27372821
27382822 if (tmfc -> iw )
27392823 isoweek2date (tmfc -> iw , & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday );
0 commit comments