From 38d9a1b580f3083ade5f18a42729e1b982ad9a4c Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Fri, 24 Apr 2026 14:38:00 +0530 Subject: [PATCH] Add regression tests for to_date()/to_timestamp() zero month/day handling Zero values for month and day fields in to_date() and to_timestamp() format strings are intentionally treated as missing data and default to 1 (January / day-of-month 1), matching the ZERO_tm() initialization in formatting.c. Add tests documenting this long-standing behavior. Reported-by: Ayush Tiwari Discussion: https://postgr.es/m/CAJTYsWWNfF+hMpbsTDF8NMr+AuqoDfNxR=oHUZm7xqGP+dJ9rA@mail.gmail.com --- src/test/regress/expected/horology.out | 33 ++++++++++++++++++++++++++ src/test/regress/sql/horology.sql | 9 +++++++ 2 files changed, 42 insertions(+) diff --git a/src/test/regress/expected/horology.out b/src/test/regress/expected/horology.out index 32cf62b6741..4bb59e69545 100644 --- a/src/test/regress/expected/horology.out +++ b/src/test/regress/expected/horology.out @@ -3778,6 +3778,39 @@ SELECT to_timestamp('613566758', 'W'); ERROR: date/time field value out of range: "613566758" SELECT to_timestamp('2024 613566758 1', 'YYYY WW D'); ERROR: date/time field value out of range: "2024 613566758 1" +-- Zero month/day values are treated as missing data and default to 1 +-- (see ZERO_tm() in formatting.c which initializes tm_mon = tm_mday = 1, +-- and do_to_timestamp() which only overwrites them for non-zero parsed values) +SELECT to_date('2024-00-15', 'YYYY-MM-DD'); -- month 0 -> defaults to January + to_date +------------ + 01-15-2024 +(1 row) + +SELECT to_date('2024-01-00', 'YYYY-MM-DD'); -- day 0 -> defaults to day 1 + to_date +------------ + 01-01-2024 +(1 row) + +SELECT to_date('2024-00-00', 'YYYY-MM-DD'); -- both zero -> Jan 1 + to_date +------------ + 01-01-2024 +(1 row) + +SELECT to_timestamp('2024-00-15', 'YYYY-MM-DD'); -- same behavior for to_timestamp + to_timestamp +------------------------------ + Mon Jan 15 00:00:00 2024 PST +(1 row) + +SELECT to_timestamp('2024-01-00', 'YYYY-MM-DD'); + to_timestamp +------------------------------ + Mon Jan 01 00:00:00 2024 PST +(1 row) + SELECT to_date('2016-13-10', 'YYYY-MM-DD'); ERROR: date/time field value out of range: "2016-13-10" SELECT to_date('2016-02-30', 'YYYY-MM-DD'); diff --git a/src/test/regress/sql/horology.sql b/src/test/regress/sql/horology.sql index 8978249a5dc..48bbf14a210 100644 --- a/src/test/regress/sql/horology.sql +++ b/src/test/regress/sql/horology.sql @@ -660,6 +660,15 @@ SELECT to_timestamp('1000000000,999', 'Y,YYY'); SELECT to_timestamp('0.-2147483648', 'SS.MS'); SELECT to_timestamp('613566758', 'W'); SELECT to_timestamp('2024 613566758 1', 'YYYY WW D'); +-- Zero month/day values are treated as missing data and default to 1 +-- (see ZERO_tm() in formatting.c which initializes tm_mon = tm_mday = 1, +-- and do_to_timestamp() which only overwrites them for non-zero parsed values) +SELECT to_date('2024-00-15', 'YYYY-MM-DD'); -- month 0 -> defaults to January +SELECT to_date('2024-01-00', 'YYYY-MM-DD'); -- day 0 -> defaults to day 1 +SELECT to_date('2024-00-00', 'YYYY-MM-DD'); -- both zero -> Jan 1 +SELECT to_timestamp('2024-00-15', 'YYYY-MM-DD'); -- same behavior for to_timestamp +SELECT to_timestamp('2024-01-00', 'YYYY-MM-DD'); + SELECT to_date('2016-13-10', 'YYYY-MM-DD'); SELECT to_date('2016-02-30', 'YYYY-MM-DD'); SELECT to_date('2016-02-29', 'YYYY-MM-DD'); -- ok -- 2.34.1