Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wFYPG-005IN6-1b for pgsql-bugs@arkaria.postgresql.org; Wed, 22 Apr 2026 14:18:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wFYPF-00DwB6-2i for pgsql-bugs@arkaria.postgresql.org; Wed, 22 Apr 2026 14:18:21 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wFYPF-00DwAy-1T for pgsql-bugs@lists.postgresql.org; Wed, 22 Apr 2026 14:18:21 +0000 Received: from mail-yw1-x1133.google.com ([2607:f8b0:4864:20::1133]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wFYP8-00000002GMZ-290S for pgsql-bugs@lists.postgresql.org; Wed, 22 Apr 2026 14:18:20 +0000 Received: by mail-yw1-x1133.google.com with SMTP id 00721157ae682-7a4f9cf2b4eso43786177b3.3 for ; Wed, 22 Apr 2026 07:18:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776867494; cv=none; d=google.com; s=arc-20240605; b=C6mK9WlMaKxt7/bhGYsba2MhwJSOJaAqp3HPPGFsMH0r8AfhJ10kzBrW3S4Dnui8lz 0XurIgYTlDquzuQ+HyWx/dgMkGJ5+ClV0QEkC5NP5+Sg6qdaQjfqTaXW21TEMKS7cRzT SdnCGjx8AFa1b7k49VboYxjAqOD93G75wpG5+qKMfSCerqc++uFv9pA1XmnJugPq7vMa FRIBQM/B879j16o1fNzSnMUd7HEwDC48agd94yHw7HIC+YUuSL3qfbY5l2Pqh20VKb2K IxNLqaxkGDPLlwHCqWvk1LsHuk2pL+j0OUQKWXNanMbWzgDXJhy0dJnIsy8BIA6WMcby bXYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=nGyjEi8p1F1kIEToKkiv7/XaTC+1kmMdwH5VOBqz/xU=; fh=/gQe77b11iMZdcPj/nJr/Ghqi6rQp5FPrPbdO93bmOA=; b=YB6VhbgZDk14L/T08TliYTki5s52dVvB4vzMWGtvRogIhnxILkHGEE+fVgZ8Sa7r3v TjeA1johSvdtIMcDoqDwjWPYa6apJaVe8u8SiCo1KWuheBenYr85hq0W7SWtZYkiEwsQ Yq8JO91YJK/rvQ0zWZkSkZqEdVXwRFt0Pj11oGeGvyaYqAwPS8I0hyOiWkJVgwq0mNgK NF/n8APOO5s86J+pSdIb3HsNXeMjh8IzjROx/b0G4qldH/zNt6JW+mIVVvlie7UUP7bl f1IQJidMbIM03jYUBN/sxgp4RUdcnNpmQ/wHfMHqlq140xdJAsnkWAsZFliVLlHKSvlP ngcA==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776867494; x=1777472294; darn=lists.postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=nGyjEi8p1F1kIEToKkiv7/XaTC+1kmMdwH5VOBqz/xU=; b=gRvZsl3cy0EgIFny1J+x6peCqTQmu5KYcMbqNB29pMhSVDQia/iwzxtLiRFuqvBEbH GkC0NCrnsqlwVGp2rf3H11PHwyPG8fjjSVOK9vfzUqiqr4rVkwfyH/xjWANfaJnjOZKA 2stRR0FOQC3WgRqC4qTroAQF4rtPCB4KD6wjiuYExEc3SjRqbzcI2L2+frDS4rXvxjc5 F9dt/h5zfiJDinHNKoV01jeEdRsI0bJliF9eDgSqIHYY/1PL+HJ51tsY7Cu6SWRK3rXB xQJvm9ffW/acLE/KYoOR62+UBV8LcMlHaUJ4b9mvG7yIBmJDrV6MgFaZKeyJe3oXrNkl avZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776867494; x=1777472294; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=nGyjEi8p1F1kIEToKkiv7/XaTC+1kmMdwH5VOBqz/xU=; b=QTPoqZ5cvI46lmHNLqSHVUek68ppaR4W2ewW3AvQPY2F8HVBancG/b0xsI9/iolhxs aY4GBieGA5ax3Z9oXH9z0vX21QmlzpFi0jfT57my9oWfbzfAHzikUbkEyiDNhqt8iELM hoB0L0v8hJ0hhbcf5STsFq9qTH0HQIIqp8IDr5FFKu24a/YJ1clCVfVq4uqrKyz2JP37 H5pn9X1lev6L1XuSCvT8t5PDinn/uoOq4WQzvKJ3EAgucYHlXXxbnh95Q0grfvYcjQ/3 XSVpnkpgolhkx62ww7oOhgjVIcNFcCke3oAESwTNnv8VyjA8Qd5Ng2D4VgT67GIMe8qV RbYA== X-Gm-Message-State: AOJu0YzrKq0kgG7TxVwRkwrTtL/qY0xsVpKIupIViTYmQeXHvu8H8c/r xBDyrBRsiis16pHjZiZmjsELNnBQZE1GieLO1N00S4JUW81bsZqdFw9NBXaMn68RzvwqfOSN1UH MolHmspTgU+UO53A/JlULLvCpURx3SCeHs8ylFKo= X-Gm-Gg: AeBDietBPFgDcaoyQPDvQOxRWGudV0JQYdGn0CbqKKU3L8cGpMzY5+kv2KMCxFqXBrJ 3VMIfoBcVdqs95ejFt4CzXYjpoXRhEVNQbpL3zmrXGChmcw0EKWOHJXbTxjFYbeCVeoR/BQEZtg 5jqyxN2F4Xot+nmTCQrRt+NcdamxgYwo3UVG+ydHl98Gnw5K/yk9x0+I6P/C4lDs6VVEjXO9cU3 m5pCIxiAN5wqnLkJAoRHf39vPcjlFWs0vDFxgd2FcSBJbhBYcPwa5lU6ktlsWuEHtAwWYIXDZGQ 3Mo9NvrexOy59qQyZJA= X-Received: by 2002:a05:690c:6e81:b0:7b3:b0a6:2c76 with SMTP id 00721157ae682-7b9ecec9907mr220797297b3.18.1776867493450; Wed, 22 Apr 2026 07:18:13 -0700 (PDT) MIME-Version: 1.0 From: Ayush Tiwari Date: Wed, 22 Apr 2026 19:48:00 +0530 X-Gm-Features: AQROBzAqPpgtVUfE5xetc76aBo6y0tnMiKFwizkVqjZVNLw-H1W1H6ezN4kJrK4 Message-ID: Subject: to_date()/to_timestamp() silently accept month=0 and day=0 To: pgsql-bugs@lists.postgresql.org Content-Type: multipart/alternative; boundary="000000000000c296de06500d33c1" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000c296de06500d33c1 Content-Type: text/plain; charset="UTF-8" Hi, I found what looks like a bug in to_date() / to_timestamp(). (Saw it in master branch) Inputs with month = 00 or day = 00 are accepted silently and normalized to January / day 1, instead of being rejected as out of range. Simple repro steps: SELECT to_date('2024-00-15', 'YYYY-MM-DD'); SELECT to_date('2024-01-00', 'YYYY-MM-DD'); SELECT to_timestamp('2024-00-15', 'YYYY-MM-DD'); SELECT to_timestamp('2024-01-00', 'YYYY-MM-DD'); Observed results here: to_date('2024-00-15', 'YYYY-MM-DD') -> 2024-01-15 to_date('2024-01-00', 'YYYY-MM-DD') -> 2024-01-01 to_timestamp('2024-00-15', 'YYYY-MM-DD') -> 2024-01-15 00:00:00+05:30 to_timestamp('2024-01-00', 'YYYY-MM-DD') -> 2024-01-01 00:00:00+05:30 I would expect all four calls to error, similar to how an invalid date literal is rejected. Looking at the root cause in src/backend/utils/adt/formatting.c, the issue seems rooted in the interaction between ZERO_tm() and do_to_timestamp(). When to_date()/to_timestamp() initializes pg_tm, it uses ZERO_tm() which defaults tm->tm_mday = 1 and tm->tm_mon = 1. The TmFromChar struct (tmfc), which is used to collect the parsed inputs, stores these fields as plain integers without independent presence flags (has_mm or has_dd have booleans). In do_to_timestamp(), the parsed values are applied back into the pg_tm struct using simple truthiness checks: if (tmfc.mm) tm->tm_mon = tmfc.mm; if (tmfc.dd) tm->tm_mday = tmfc.dd; Because an explicitly parsed 00 evaluates to false, the zeros are never copied into pg_tm. Thus, the 1 defaults from ZERO_tm() remain untouched, and the subsequent validation function ValidateDate() never actually sees the 0 to throw an out-of-bounds error. Fixing this likely requires adding boolean flags to TmFromChar to distinguish between an omitted field and an explicitly parsed 0? Regards, Ayush --000000000000c296de06500d33c1 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi,

I found what looks like a bug in to_date() / to= _timestamp(). (Saw it in master branch)

Inputs with month =3D 00 or = day =3D 00 are accepted silently and normalized to
January / day 1, inst= ead of being rejected as out of range.

Simple repro steps:

SE= LECT to_date('2024-00-15', 'YYYY-MM-DD');
SELECT to_date= ('2024-01-00', 'YYYY-MM-DD');
SELECT to_timestamp('2= 024-00-15', 'YYYY-MM-DD');
SELECT to_timestamp('2024-01-= 00', 'YYYY-MM-DD');

Observed results here:

=C2=A0= to_date('2024-00-15', 'YYYY-MM-DD') =C2=A0 =C2=A0 =C2=A0-&= gt; 2024-01-15
=C2=A0 to_date('2024-01-00', 'YYYY-MM-DD'= ) =C2=A0 =C2=A0 =C2=A0-> 2024-01-01
=C2=A0 to_timestamp('2024-00-= 15', 'YYYY-MM-DD') -> 2024-01-15 00:00:00+05:30
=C2=A0 to= _timestamp('2024-01-00', 'YYYY-MM-DD') -> 2024-01-01 00:= 00:00+05:30

I would expect all four calls to error, similar to how a= n invalid date literal
is rejected.

Looking at the root cause in = src/backend/utils/adt/formatting.c, the issue seems
rooted in the intera= ction between ZERO_tm() and do_to_timestamp().

When to_date()/to_tim= estamp() initializes pg_tm, it uses ZERO_tm() which
defaults tm->tm_m= day =3D 1 and tm->tm_mon =3D 1. The TmFromChar struct (tmfc),
which i= s used to collect the parsed inputs, stores these fields as plain
integ= ers without independent presence flags (has_mm or has_dd have booleans).
In do_to_timestamp(), the parsed values are applied back into the pg_= tm struct
using simple truthiness checks:

=C2=A0 =C2=A0 if (tmfc.mm) tm->tm_mon =3D tmfc.mm;
=C2=A0 =C2=A0 if (tmfc.dd) tm->tm_mday =3D tmfc.dd= ;

Because an explicitly parsed 00 evaluates to false, the zeros are = never copied
into pg_tm. Thus, the 1 defaults from ZERO_tm() remain unto= uched, and the
subsequent validation function ValidateDate() never actua= lly sees the 0 to throw
an out-of-bounds error.

Fixing this like= ly requires adding boolean flags to TmFromChar to distinguish
between a= n omitted field and an explicitly parsed 0?

Regards,
Ayush
--000000000000c296de06500d33c1--