commit 4811b710256b1d42ca5b967b774669959267f06c Author: Alexander Korotkov Date: Tue Aug 20 07:57:11 2019 +0300 Introduce RR and RRRR, revise YYY, YY and Y format patterns Reported-by: Bug: Discussion: Author: Reviewed-by: Tested-by: Backpatch-through: diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 481ef93941e..9ebcdad3cf9 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -626,6 +626,8 @@ typedef enum DCH_PM, DCH_Q, DCH_RM, + DCH_RRRR, + DCH_RR, DCH_SSSSS, DCH_SSSS, DCH_SS, @@ -679,6 +681,8 @@ typedef enum DCH_pm, DCH_q, DCH_rm, + DCH_rrrr, + DCH_rr, DCH_sssss, DCH_ssss, DCH_ss, @@ -789,6 +793,8 @@ static const KeyWord DCH_keywords[] = { {"PM", 2, DCH_PM, false, FROM_CHAR_DATE_NONE}, {"Q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* Q */ {"RM", 2, DCH_RM, false, FROM_CHAR_DATE_GREGORIAN}, /* R */ + {"RRRR", 4, DCH_RRRR, true, FROM_CHAR_DATE_GREGORIAN}, + {"RR", 2, DCH_RR, true, FROM_CHAR_DATE_GREGORIAN}, {"SSSSS", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, /* S */ {"SSSS", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, {"SS", 2, DCH_SS, true, FROM_CHAR_DATE_NONE}, @@ -842,6 +848,8 @@ static const KeyWord DCH_keywords[] = { {"pm", 2, DCH_pm, false, FROM_CHAR_DATE_NONE}, {"q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* q */ {"rm", 2, DCH_rm, false, FROM_CHAR_DATE_GREGORIAN}, /* r */ + {"rrrr", 4, DCH_RRRR, true, FROM_CHAR_DATE_GREGORIAN}, + {"rr", 2, DCH_RR, true, FROM_CHAR_DATE_GREGORIAN}, {"sssss", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, /* s */ {"ssss", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, {"ss", 2, DCH_SS, true, FROM_CHAR_DATE_NONE}, @@ -1013,7 +1021,8 @@ static void dump_node(FormatNode *node, int max); static const char *get_th(char *num, int type); static char *str_numth(char *dest, char *num, int type); -static int adjust_partial_year_to_2020(int year); +static int adjust_partial_year_to_2020(int year, int ndigits); +static int adjust_relative_partial_year_to_2020(int year); static int strspace_len(char *str); static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode); static void from_char_set_int(int *dest, const int value, const FormatNode *node); @@ -2157,7 +2166,19 @@ is_next_separator(FormatNode *n) static int -adjust_partial_year_to_2020(int year) +adjust_partial_year_to_2020(int year, int ndigits) +{ + if (ndigits == 1) + return year + 2020; + else if (ndigits == 2 || ndigits == 3) + return year + 2000; + else + return year; +} + + +static int +adjust_relative_partial_year_to_2020(int year) { /* * Adjust all dates toward 2020; this is effectively what happens when we @@ -2958,6 +2979,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; + case DCH_RRRR: case DCH_YYYY: case DCH_IYYY: sprintf(s, "%0*d", @@ -2988,6 +3010,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; + case DCH_RR: case DCH_YY: case DCH_IY: sprintf(s, "%0*d", @@ -3373,6 +3396,7 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) SKIP_THth(s, n->suffix); } break; + case DCH_RRRR: case DCH_YYYY: case DCH_IYYY: from_char_parse_int(&out->year, &s, n); @@ -3381,22 +3405,28 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out) break; case DCH_YYY: case DCH_IYY: - if (from_char_parse_int(&out->year, &s, n) < 4) - out->year = adjust_partial_year_to_2020(out->year); + len = from_char_parse_int(&out->year, &s, n); + out->year = adjust_partial_year_to_2020(out->year, len); out->yysz = 3; SKIP_THth(s, n->suffix); break; + case DCH_RR: + from_char_parse_int(&out->year, &s, n); + out->year = adjust_relative_partial_year_to_2020(out->year); + out->yysz = 2; + SKIP_THth(s, n->suffix); + break; case DCH_YY: case DCH_IY: - if (from_char_parse_int(&out->year, &s, n) < 4) - out->year = adjust_partial_year_to_2020(out->year); + len = from_char_parse_int(&out->year, &s, n); + out->year = adjust_partial_year_to_2020(out->year, len); out->yysz = 2; SKIP_THth(s, n->suffix); break; case DCH_Y: case DCH_I: - if (from_char_parse_int(&out->year, &s, n) < 4) - out->year = adjust_partial_year_to_2020(out->year); + len = from_char_parse_int(&out->year, &s, n); + out->year = adjust_partial_year_to_2020(out->year, len); out->yysz = 1; SKIP_THth(s, n->suffix); break; diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index 6b53876e062..f68882cc173 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -2597,7 +2597,7 @@ SELECT to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD'); (1 row) SELECT to_timestamp('15 "text between quote marks" 98 54 45', - E'HH24 "\\"text between quote marks\\"" YY MI SS'); + E'HH24 "\\"text between quote marks\\"" RR MI SS'); to_timestamp ------------------------------ Thu Jan 01 15:54:45 1998 PST @@ -2618,19 +2618,22 @@ SELECT to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay'); SELECT to_timestamp('97/Feb/16', 'YYMonDD'); ERROR: invalid value "/Fe" for "Mon" DETAIL: The given value did not match any of the allowed values for this field. +SELECT to_timestamp('97/Feb/16', 'RRMonDD'); +ERROR: invalid value "/Fe" for "Mon" +DETAIL: The given value did not match any of the allowed values for this field. SELECT to_timestamp('97/Feb/16', 'YY:Mon:DD'); to_timestamp ------------------------------ - Sun Feb 16 00:00:00 1997 PST + Sat Feb 16 00:00:00 2097 PST (1 row) -SELECT to_timestamp('97/Feb/16', 'FXYY:Mon:DD'); +SELECT to_timestamp('97/Feb/16', 'FXRR:Mon:DD'); to_timestamp ------------------------------ Sun Feb 16 00:00:00 1997 PST (1 row) -SELECT to_timestamp('97/Feb/16', 'FXYY/Mon/DD'); +SELECT to_timestamp('97/Feb/16', 'FXRR/Mon/DD'); to_timestamp ------------------------------ Sun Feb 16 00:00:00 1997 PST @@ -2642,6 +2645,12 @@ SELECT to_timestamp('19971116', 'YYYYMMDD'); Sun Nov 16 00:00:00 1997 PST (1 row) +SELECT to_timestamp('19971116', 'RRRRMMDD'); + to_timestamp +------------------------------ + Sun Nov 16 00:00:00 1997 PST +(1 row) + SELECT to_timestamp('20000-1116', 'YYYY-MMDD'); to_timestamp ------------------------------- @@ -2663,11 +2672,17 @@ SELECT to_timestamp('1997 BC 11 16', 'YYYY BC MM DD'); SELECT to_timestamp('9-1116', 'Y-MMDD'); to_timestamp ------------------------------ - Mon Nov 16 00:00:00 2009 PST + Fri Nov 16 00:00:00 2029 PST (1 row) SELECT to_timestamp('95-1116', 'YY-MMDD'); to_timestamp +------------------------------ + Wed Nov 16 00:00:00 2095 PST +(1 row) + +SELECT to_timestamp('95-1116', 'RR-MMDD'); + to_timestamp ------------------------------ Thu Nov 16 00:00:00 1995 PST (1 row) @@ -2675,7 +2690,7 @@ SELECT to_timestamp('95-1116', 'YY-MMDD'); SELECT to_timestamp('995-1116', 'YYY-MMDD'); to_timestamp ------------------------------ - Thu Nov 16 00:00:00 1995 PST + Mon Nov 16 00:00:00 2995 PST (1 row) SELECT to_timestamp('2005426', 'YYYYWWD'); @@ -2711,7 +2726,7 @@ SELECT to_timestamp('05527', 'IYIWID'); SELECT to_timestamp('5527', 'IIWID'); to_timestamp ------------------------------ - Sun Jan 01 00:00:00 2006 PST + Sun Dec 28 00:00:00 2025 PST (1 row) SELECT to_timestamp('2005364', 'IYYYIDDD'); diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql index f7a9da1e954..e35cb448508 100644 --- a/src/test/regress/sql/horology.sql +++ b/src/test/regress/sql/horology.sql @@ -344,7 +344,7 @@ SELECT to_timestamp('My birthday-> Year: 1976, Month: May, Day: 16', SELECT to_timestamp('1,582nd VIII 21', 'Y,YYYth FMRM DD'); SELECT to_timestamp('15 "text between quote marks" 98 54 45', - E'HH24 "\\"text between quote marks\\"" YY MI SS'); + E'HH24 "\\"text between quote marks\\"" RR MI SS'); SELECT to_timestamp('05121445482000', 'MMDDHH24MISSYYYY'); @@ -352,14 +352,18 @@ SELECT to_timestamp('2000January09Sunday', 'YYYYFMMonthDDFMDay'); SELECT to_timestamp('97/Feb/16', 'YYMonDD'); +SELECT to_timestamp('97/Feb/16', 'RRMonDD'); + SELECT to_timestamp('97/Feb/16', 'YY:Mon:DD'); -SELECT to_timestamp('97/Feb/16', 'FXYY:Mon:DD'); +SELECT to_timestamp('97/Feb/16', 'FXRR:Mon:DD'); -SELECT to_timestamp('97/Feb/16', 'FXYY/Mon/DD'); +SELECT to_timestamp('97/Feb/16', 'FXRR/Mon/DD'); SELECT to_timestamp('19971116', 'YYYYMMDD'); +SELECT to_timestamp('19971116', 'RRRRMMDD'); + SELECT to_timestamp('20000-1116', 'YYYY-MMDD'); SELECT to_timestamp('1997 AD 11 16', 'YYYY BC MM DD'); @@ -369,6 +373,8 @@ SELECT to_timestamp('9-1116', 'Y-MMDD'); SELECT to_timestamp('95-1116', 'YY-MMDD'); +SELECT to_timestamp('95-1116', 'RR-MMDD'); + SELECT to_timestamp('995-1116', 'YYY-MMDD'); SELECT to_timestamp('2005426', 'YYYYWWD');