Skip to content

Commit 029dfdf

Browse files
committed
Fix to_date() and to_timestamp() to handle year masks of length < 4 so
they wrap toward year 2020, rather than the inconsistent behavior we had before.
1 parent 8eacb25 commit 029dfdf

File tree

2 files changed

+41
-26
lines changed

2 files changed

+41
-26
lines changed

doc/src/sgml/func.sgml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5548,6 +5548,15 @@ SELECT SUBSTRING('XY1234Z', 'Y*?([0-9]{1,3})');
55485548
</para>
55495549
</listitem>
55505550

5551+
<listitem>
5552+
<para>
5553+
If the year format specification is less than four digits, e.g.
5554+
<literal>YYY</>, and the supplied year is less than four digits,
5555+
the year will be adjusted to be nearest to the year 2020, e.g.
5556+
<literal>95</> becomes 1995.
5557+
</para>
5558+
</listitem>
5559+
55515560
<listitem>
55525561
<para>
55535562
The <literal>YYYY</literal> conversion from string to <type>timestamp</type> or

src/backend/utils/adt/formatting.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ static void dump_node(FormatNode *node, int max);
964964

965965
static char *get_th(char *num, int type);
966966
static char *str_numth(char *dest, char *num, int type);
967+
static int adjust_partial_year_to_2020(int year);
967968
static int strspace_len(char *str);
968969
static int strdigits_len(char *str);
969970
static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
@@ -1968,6 +1969,31 @@ is_next_separator(FormatNode *n)
19681969
return TRUE; /* some non-digit input (separator) */
19691970
}
19701971

1972+
1973+
static int
1974+
adjust_partial_year_to_2020(int year)
1975+
{
1976+
/*
1977+
* Adjust all dates toward 2020; this is effectively what happens
1978+
* when we assume '70' is 1970 and '69' is 2069.
1979+
*/
1980+
/* Force 0-69 into the 2000's */
1981+
if (year < 70)
1982+
return year + 2000;
1983+
/* Force 70-99 into the 1900's */
1984+
else if (year >= 70 && year < 100)
1985+
return year + 1900;
1986+
/* Force 100-519 into the 2000's */
1987+
else if (year >= 100 && year < 519)
1988+
return year + 2000;
1989+
/* Force 520-999 into the 1000's */
1990+
else if (year >= 520 && year < 1000)
1991+
return year + 1000;
1992+
else
1993+
return year;
1994+
}
1995+
1996+
19711997
static int
19721998
strspace_len(char *str)
19731999
{
@@ -2930,43 +2956,23 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
29302956
break;
29312957
case DCH_YYY:
29322958
case DCH_IYY:
2933-
from_char_parse_int(&out->year, &s, n);
2959+
if (from_char_parse_int(&out->year, &s, n) < 4)
2960+
out->year = adjust_partial_year_to_2020(out->year);
29342961
out->yysz = 3;
2935-
2936-
/*
2937-
* 3-digit year: '100' ... '999' = 1100 ... 1999 '000' ...
2938-
* '099' = 2000 ... 2099
2939-
*/
2940-
if (out->year >= 100)
2941-
out->year += 1000;
2942-
else
2943-
out->year += 2000;
29442962
s += SKIP_THth(n->suffix);
29452963
break;
29462964
case DCH_YY:
29472965
case DCH_IY:
2948-
from_char_parse_int(&out->year, &s, n);
2966+
if (from_char_parse_int(&out->year, &s, n) < 4)
2967+
out->year = adjust_partial_year_to_2020(out->year);
29492968
out->yysz = 2;
2950-
2951-
/*
2952-
* 2-digit year: '00' ... '69' = 2000 ... 2069 '70' ... '99'
2953-
* = 1970 ... 1999
2954-
*/
2955-
if (out->year < 70)
2956-
out->year += 2000;
2957-
else
2958-
out->year += 1900;
29592969
s += SKIP_THth(n->suffix);
29602970
break;
29612971
case DCH_Y:
29622972
case DCH_I:
2963-
from_char_parse_int(&out->year, &s, n);
2973+
if (from_char_parse_int(&out->year, &s, n) < 4)
2974+
out->year = adjust_partial_year_to_2020(out->year);
29642975
out->yysz = 1;
2965-
2966-
/*
2967-
* 1-digit year: always +2000
2968-
*/
2969-
out->year += 2000;
29702976
s += SKIP_THth(n->suffix);
29712977
break;
29722978
case DCH_RM:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy