Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 489c9c3

Browse files
committed
Fix handling of BC years in to_date/to_timestamp.
Previously, a conversion such as to_date('-44-02-01','YYYY-MM-DD') would result in '0045-02-01 BC', as the code attempted to interpret the negative year as BC, but failed to apply the correction needed for our internal handling of BC years. Fix the off-by-one problem. Also, arrange for the combination of a negative year and an explicit "BC" marker to cancel out and produce AD. This is how the negative-century case works, so it seems sane to do likewise. Continue to read "year 0000" as 1 BC. Oracle would throw an error, but we've accepted that case for a long time so I'm hesitant to change it in a back-patch. Per bug #16419 from Saeed Hubaishan. Back-patch to all supported branches. Dar Alathar-Yemen and Tom Lane Discussion: https://postgr.es/m/16419-d8d9db0a7553f01b@postgresql.org
1 parent 9796f45 commit 489c9c3

File tree

4 files changed

+71
-2
lines changed

4 files changed

+71
-2
lines changed

doc/src/sgml/func.sgml

+9
Original file line numberDiff line numberDiff line change
@@ -7678,6 +7678,15 @@ SELECT regexp_match('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}');
76787678
</para>
76797679
</listitem>
76807680

7681+
<listitem>
7682+
<para>
7683+
In <function>to_timestamp</function> and <function>to_date</function>,
7684+
negative years are treated as signifying BC. If you write both a
7685+
negative year and an explicit <literal>BC</literal> field, you get AD
7686+
again. An input of year zero is treated as 1 BC.
7687+
</para>
7688+
</listitem>
7689+
76817690
<listitem>
76827691
<para>
76837692
In <function>to_timestamp</function> and <function>to_date</function>,

src/backend/utils/adt/formatting.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -4569,8 +4569,11 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
45694569
{
45704570
/* If a 4-digit year is provided, we use that and ignore CC. */
45714571
tm->tm_year = tmfc.year;
4572-
if (tmfc.bc && tm->tm_year > 0)
4573-
tm->tm_year = -(tm->tm_year - 1);
4572+
if (tmfc.bc)
4573+
tm->tm_year = -tm->tm_year;
4574+
/* correct for our representation of BC years */
4575+
if (tm->tm_year < 0)
4576+
tm->tm_year++;
45744577
}
45754578
fmask |= DTK_M(YEAR);
45764579
}

src/test/regress/expected/horology.out

+45
Original file line numberDiff line numberDiff line change
@@ -2916,6 +2916,45 @@ SELECT to_date('2458872', 'J');
29162916
01-23-2020
29172917
(1 row)
29182918

2919+
--
2920+
-- Check handling of BC dates
2921+
--
2922+
SELECT to_date('44-02-01 BC','YYYY-MM-DD BC');
2923+
to_date
2924+
---------------
2925+
02-01-0044 BC
2926+
(1 row)
2927+
2928+
SELECT to_date('-44-02-01','YYYY-MM-DD');
2929+
to_date
2930+
---------------
2931+
02-01-0044 BC
2932+
(1 row)
2933+
2934+
SELECT to_date('-44-02-01 BC','YYYY-MM-DD BC');
2935+
to_date
2936+
------------
2937+
02-01-0044
2938+
(1 row)
2939+
2940+
SELECT to_timestamp('44-02-01 11:12:13 BC','YYYY-MM-DD HH24:MI:SS BC');
2941+
to_timestamp
2942+
---------------------------------
2943+
Fri Feb 01 11:12:13 0044 PST BC
2944+
(1 row)
2945+
2946+
SELECT to_timestamp('-44-02-01 11:12:13','YYYY-MM-DD HH24:MI:SS');
2947+
to_timestamp
2948+
---------------------------------
2949+
Fri Feb 01 11:12:13 0044 PST BC
2950+
(1 row)
2951+
2952+
SELECT to_timestamp('-44-02-01 11:12:13 BC','YYYY-MM-DD HH24:MI:SS BC');
2953+
to_timestamp
2954+
------------------------------
2955+
Mon Feb 01 11:12:13 0044 PST
2956+
(1 row)
2957+
29192958
--
29202959
-- Check handling of multiple spaces in format and/or input
29212960
--
@@ -3183,6 +3222,12 @@ SELECT to_date('2016 366', 'YYYY DDD'); -- ok
31833222

31843223
SELECT to_date('2016 367', 'YYYY DDD');
31853224
ERROR: date/time field value out of range: "2016 367"
3225+
SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
3226+
to_date
3227+
---------------
3228+
02-01-0001 BC
3229+
(1 row)
3230+
31863231
--
31873232
-- Check behavior with SQL-style fixed-GMT-offset time zone (cf bug #8572)
31883233
--

src/test/regress/sql/horology.sql

+12
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,17 @@ SELECT to_date('1 4 1902', 'Q MM YYYY'); -- Q is ignored
426426
SELECT to_date('3 4 21 01', 'W MM CC YY');
427427
SELECT to_date('2458872', 'J');
428428

429+
--
430+
-- Check handling of BC dates
431+
--
432+
433+
SELECT to_date('44-02-01 BC','YYYY-MM-DD BC');
434+
SELECT to_date('-44-02-01','YYYY-MM-DD');
435+
SELECT to_date('-44-02-01 BC','YYYY-MM-DD BC');
436+
SELECT to_timestamp('44-02-01 11:12:13 BC','YYYY-MM-DD HH24:MI:SS BC');
437+
SELECT to_timestamp('-44-02-01 11:12:13','YYYY-MM-DD HH24:MI:SS');
438+
SELECT to_timestamp('-44-02-01 11:12:13 BC','YYYY-MM-DD HH24:MI:SS BC');
439+
429440
--
430441
-- Check handling of multiple spaces in format and/or input
431442
--
@@ -511,6 +522,7 @@ SELECT to_date('2015 366', 'YYYY DDD');
511522
SELECT to_date('2016 365', 'YYYY DDD'); -- ok
512523
SELECT to_date('2016 366', 'YYYY DDD'); -- ok
513524
SELECT to_date('2016 367', 'YYYY DDD');
525+
SELECT to_date('0000-02-01','YYYY-MM-DD'); -- allowed, though it shouldn't be
514526

515527
--
516528
-- Check behavior with SQL-style fixed-GMT-offset time zone (cf bug #8572)

0 commit comments

Comments
 (0)