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.94.2) (envelope-from ) id 1rfbo8-0019gU-EH for pgsql-odbc@arkaria.postgresql.org; Thu, 29 Feb 2024 08:30:25 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1rfbo7-001Hna-1E for pgsql-odbc@arkaria.postgresql.org; Thu, 29 Feb 2024 08:30:23 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rfa2J-000ZuK-NS for pgsql-odbc@lists.postgresql.org; Thu, 29 Feb 2024 06:36:56 +0000 Received: from mx0c-001a4c01.pphosted.com ([67.231.158.153]) by magus.postgresql.org with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rfa2G-001zW7-TB for pgsql-odbc@postgresql.org; Thu, 29 Feb 2024 06:36:55 +0000 Received: from pps.filterd (m0075701.ppops.net [127.0.0.1]) by mx0c-001a4c01.pphosted.com (8.17.1.24/8.17.1.24) with ESMTP id 41T4vNjL019849 for ; Thu, 29 Feb 2024 01:36:50 -0500 Received: from eur03-am7-obe.outbound.protection.outlook.com (mail-am7eur03lp2233.outbound.protection.outlook.com [104.47.51.233]) by mx0c-001a4c01.pphosted.com (PPS) with ESMTPS id 3wjkbv8atw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 29 Feb 2024 01:36:49 -0500 (EST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Kp8z912gGPDHZrzNFjPuuE4I+T88OHh2Fz90QKfv6PIUcEhAP6QOm8QIhRmhWG0biaiyXCPwAXqgT2YJaziFUlR4MWWnRXN2rHSdA6Kz0cWzGlPccmOY4WAozzQEhixnaBnoiWj6Cp4FRWQzjRgJ4s9ahx9k2yJCkd3oJKDQWWIYB3kq+qvyRd/OowE3eVBVzk88DuAyQ/AIyNGq2cZxgjsSoqsWzGHxtkxfJGMPhP3HETlJdKbyH99KXhzAyNT2J6QZqcUNsE4Zx+t1ncgcGpqP/Az2g+PRC6hs5dXRScfJC/jLidgY8Han5j6uj1EYqqz2Bo7HsMdzAdohuyeKcQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ywd8M6Uieg9L57Gsy5HyFttwWwFS9GeabtRigfYNxJk=; b=I+7zqpROijGIC5HniwehcmYV/vkSaPt7/u+S+XrClSqE8jSGjQ2LLvgfrC864QEBQoBQetAOIQ2gJu1WhvXCX1tI4zTSRxjl3nPaAHDIH3fvS9fdvkgeKNeA8/7RAKjECLcvEef67tc7WDga+FANuajryX1rg7JXwLMbo1IcLUQdb3dwPGbeKIWFgKSnD0DlVSugEhmKwMtsbU0zrEhGFWJjkfDML7b4LGqm+4obP+6TRz7Lkog5FzR4e7B6nzxVuP81m8WQPF4F+k86LlH4vJwnMBqXZXCOJHk2LpQMwUQI0OpSn0+PiIIBnnwhfVE9qh+tqDbrKHjTHhfHQlwnmw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=modaxo.com; dmarc=pass action=none header.from=modaxo.com; dkim=pass header.d=modaxo.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ourvolaris.onmicrosoft.com; s=selector2-ourvolaris-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ywd8M6Uieg9L57Gsy5HyFttwWwFS9GeabtRigfYNxJk=; b=MKieSCwii1x44XMuxxkKu83rZH+QM0LOK4cQnkyIlg/XIh3Y2LpADM7lhoQRO1jC86f55XJawnsbmKVmDOP2/psrw8WJpaHRdPMLCUGvAC4FyeMPWoU9Fay11e1adpI8yvkZ1S5tctOncBZNE9cMvcWHfx8Lmer4VrAAT9b3rK0= Received: from DU0P191MB2082.EURP191.PROD.OUTLOOK.COM (2603:10a6:10:346::12) by AM7P191MB0868.EURP191.PROD.OUTLOOK.COM (2603:10a6:20b:17f::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7339.25; Thu, 29 Feb 2024 06:36:43 +0000 Received: from DU0P191MB2082.EURP191.PROD.OUTLOOK.COM ([fe80::e63a:541a:ce6a:14d2]) by DU0P191MB2082.EURP191.PROD.OUTLOOK.COM ([fe80::e63a:541a:ce6a:14d2%6]) with mapi id 15.20.7362.013; Thu, 29 Feb 2024 06:36:42 +0000 From: David Gregory To: "pgsql-odbc@postgresql.org" Subject: Leap day weirdness with dates that are out of range Thread-Topic: Leap day weirdness with dates that are out of range Thread-Index: Adpq2GgehLPmISQQR3qur0GTmnBOUQ== Date: Thu, 29 Feb 2024 06:36:42 +0000 Message-ID: Accept-Language: en-AU, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: DU0P191MB2082:EE_|AM7P191MB0868:EE_ x-ms-office365-filtering-correlation-id: 5d106b2f-b614-49c9-3d25-08dc38f0cac2 x-volarisppoutbound: true x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: suE7rkuBLUiNMpZDbWeN0yyRq8Hq7fMHHPzAaB8uZuU9vbM9RYmfoCT7A0Eyx/DP3WVOffCofErSWmhFe3b3BotPs2ImLYrLnjP+GMQU9cHkMX5lw7tGdjK15IIBdCA0rQiLhpP8n4JmCKzSVYbHeZOnr6ms+GkRSHYiAcJ79rFqvhtI6u4OcVisPCqDuD0J/a1ZT7J/txAMiMOpGsGoiMVST6VzgaIJtpg3qfKUFzzT/bTKrao3SBs6GwkGKszmIRPW7r4lEE4EnxDtz3MLJBezsTsk9kkON4hleJ9n4aaAZNF4vEtLsFz41QEprpzyan8yVpXAYxKaWkdhYy7H2Uyk2EEgxVstAoS9yNy/Hov8MayaXkLj2J4raMmZqLCHcS25vGkDlfk79h1VwxMTxlzkDuzK3u1ph02sdquOoqHOMZdNiCxfcmtmuG3WHAuDpeA+WpyKjzZissAG/4kYX1dDO0Yx8ubVjJT7OZ+q688+lo+RkOA6SM2Xv/XHFntHPkC9rlOtw7MzkxoxEWCqK+fL9xuPDBK+jQGPjYwUE1qOHhkDQCQPxJZfSdOuZJS8j6WIIiEuygoS/9Mt2gISMGLyXpX+LSSKLk5NNX9TzxZKSOeayLXJlP7Ba6iyzUzhTZXt97O9FTpsIssRa3+jJSHxH/I1+xYMCZpV57njxSpngVw06p2Fsdux1eM6k2F/qDPTOpj3hhqIlGUcnjMVTsJ2aqBzkLpGT+aN5O4syGE= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DU0P191MB2082.EURP191.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230031)(38070700009);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?vljhKkxt451OPlaaV2F6s3O4lrFD9xxtqFp6mGgwjefv/Rd1uqMGOyoJM3Zs?= =?us-ascii?Q?O6xLu/hucPnCvpBrgE6+Rd31I9AhGpK2sREtHZ/OFCScIGaJe6gCnhY/LXmc?= =?us-ascii?Q?dJ1ev+01x1NzASqSJ5wGY4kNeLJ3rvGtn4jUvnFKsnSmVWJfIqljP1sSYm1T?= =?us-ascii?Q?pOLtvJ5jTwcV2fD1OD5ndDBJv+m8b/AE60+XNca2tL4+AvSsJeqmyIhB36ae?= =?us-ascii?Q?ZiZzA28ep9fDoVYG1hTxptHh4bmc2pIdWQMTQQwldkSnGS9f7pPlKHamWrif?= =?us-ascii?Q?BB3pGMajkUwfMEWWLiXnd3U+/ntpsmmRbeoqWdthYlolf6H+mtCNxI9YXd8S?= =?us-ascii?Q?CmmkmtVytBIgyvMMxk4V/emf9y11fvGOMuJJ2ZuoIu+HzLKNCyBFq7TybLzK?= =?us-ascii?Q?D48wqPIqDBOksEn/EBdJQ3mx1+Ooi4/nFef7pgdE4599bVw6TMCLu83GX+N6?= =?us-ascii?Q?HRvPyZ9HTUKs1/w7eJqfw6seQPs6eE+L8/qjuJpMhHALlhUW7S4c2ssjkEEQ?= =?us-ascii?Q?rdPRqzCmWRD1MisqLtGD00RpeYADvaBzjnObp+91Uhuq5eLC3GYTAnK1TLHE?= =?us-ascii?Q?N2/DXVA/w85pxH4VyJO/81uvuksFDoHMEzTT2QbzZ8CSKXiUZLM6jHAOt82q?= =?us-ascii?Q?EuOjPAqWyBNTpyDsn1U2ym7jXCEsZpkSG5LC8b0B1yxuB+v3bvrbOEtmhVjC?= =?us-ascii?Q?LmEP8WUlyvaKEKgSPYjqJqu3tla72c6QaWNMBpAg+424ToTy0kZeBBbpjfzx?= =?us-ascii?Q?bKd5BEeA9Ulmp2N49sEWMxcaUVQA9XdG+v7Bhs7ilD8jubsTRlsgfiZ2Nssu?= =?us-ascii?Q?YAj/fqfdKzbwCt5RABA9YH14KhMTJMnL3eSngKfr9WaPpXVpLYKhMLVc7HYQ?= =?us-ascii?Q?3cJdCcNsqxfEnzjTvCNy3CclJoJsR6koEd2cE7A5h5hEddWC6+ZWxZR53N8G?= =?us-ascii?Q?Yq8OSpkdZHdvqEz/R1yCFRBzBNCraL8QE1hiGVt0RTg2g28NWPQMmTsPl5ba?= =?us-ascii?Q?O24nRH0DecC4++dhzhhihXWCovWW/o16vbzLYzPOjXlQmdSn7pAZb81PdEb9?= =?us-ascii?Q?ajLEW/pppjisFU539DGtZTGHAwUuS3WwuphutzaYOxeBM9tM7For/0MG0yec?= =?us-ascii?Q?WZi1ApWirQ4/F5jbET0Ntsql0R1++hKpRyCjg2y49K0sqCViBnNtHuEQDLdI?= =?us-ascii?Q?OGXGJ+ICnWoZSlMmcp6azWoLdItpDTZQWujZlmibDhirdLZ54GGR9RMUHNnV?= =?us-ascii?Q?KtfVc1olrJSbMQtpGYQvXir0nH9t6UgpOGhImkhd9CWZInilrxode+CRKgXv?= =?us-ascii?Q?6PTekIPcxLteqGa7uMhXWTSVIwFp+NsjPO4UCN935CuH90jmen8bpsIsTw4A?= =?us-ascii?Q?yoDi9dlzN/nG57RxkQPomp9y3tB2WE1QEHTpKnt4ojknYPT9v835M5HgLEBN?= =?us-ascii?Q?xE3NAUw4dxAMgTkLOl1r0+y9+4Wx/AjC/X1WBrNBuNTGynj+1uIfyO0uVqZ8?= =?us-ascii?Q?IbZjpM/UH/Pgq2lTzC468lqB7F2Uan6YfQpFqvF6IdzbL5A7NCx5wE39YjK1?= =?us-ascii?Q?Q131jeXp9n/mI7DP45LMDFeP4vX+3zSMDDibJONU?= Content-Type: multipart/alternative; boundary="_000_DU0P191MB2082B40B00EE9A8CEE50F16C865F2DU0P191MB2082EURP_" MIME-Version: 1.0 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: wZKFCzpPAAhcajPJarGY2YNkxmEacdV0B3PE2ObU2J+BqDgROYEHPbSMA3NQI7sQoG25+lF4ANWKQWN+2IXcWIcD/Rvrl7jboOkrgUhJtnSvJra7ncx5Ym8NNCr6fI12U5tslPlJhul2W5y9Rfxz09gn93jG2if4mbTmEbsuKlMdmqzUliFHPBoDZiAIdW8GMeFsjqhzRySYIfF7Z64xJVrfdnIq0bsw5tO3KmQF30owydivl1iBP0vkcsB21pMBreIg4/hOC57vTBnzKwHmbQwSETheFxqHDjhz7stj75oOqSZdDbJ0t+90LEsLL2NtXvIWMbxLlONc2eTzgsBfDZd5inodKacdMogF/f4jnbxeWu+iUJfpVtd4h1v2NyScILwHifnD1xjIpWMJuAbhvNh9IdesNJNOpmyXjCtNlbXE6k9A6zaqmIXKY8vh47SDFlF94c+s2Y3CyKf3Hlflk5jaWEfM56CJcra6t+KTpkdYrTLAFJFbb9sdYbjluumO/+s7n3JlfCzwrDUcvgxgNFm8l/RKZaoOrpU2TlqNCsmdBTiDa6gBlQBSlb76GA22vaw14I7i3zopNsuyIQRTsimyq7Eimp1yEZULbyPikxejKTurC/60nYejIGxWMScDh2phFXjmuEYhJHWUhT2tjg== X-OriginatorOrg: modaxo.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: DU0P191MB2082.EURP191.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-Network-Message-Id: 5d106b2f-b614-49c9-3d25-08dc38f0cac2 X-MS-Exchange-CrossTenant-originalarrivaltime: 29 Feb 2024 06:36:42.4423 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 75c696ec-5bfb-4892-9a0c-9187a9061cd6 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: qnI+fKAi7Aywz7tPzPCi6axoPwlVFuV/eYITxjgkD+oRoYjuCALqJx7N4lxyVXzOk8a05gXATpoh/sT2HqcY1H9KsQ6gsgWA+Z1q2CbVmrU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM7P191MB0868 X-Proofpoint-ORIG-GUID: 2uZwWyRZ4ZB_ETqo2DqP-j-MtDnJevaE X-Proofpoint-GUID: 2uZwWyRZ4ZB_ETqo2DqP-j-MtDnJevaE X-ProofpointHeader: Yes X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 phishscore=0 mlxscore=0 spamscore=0 impostorscore=0 mlxlogscore=999 suspectscore=0 priorityscore=1501 bulkscore=0 clxscore=1011 lowpriorityscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2402120000 definitions=main-2402290050 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --_000_DU0P191MB2082B40B00EE9A8CEE50F16C865F2DU0P191MB2082EURP_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable We've had an issue pop up today due to the leap day that I wanted to let yo= u know about. If a postgresql database table contains a date with more than 4 digits in t= he year, it appears that the postgresql ODBC driver does something weird: - It takes the first 4 digits of the year - It then uses todays day and month It then returns this date as the value of the column. The client software = then tries to interpret this date into its native date type which, when the= current date is the 29th Feb fails 75% of the time with a data conversion = exception due to the resulting date not existing. For example, if the date in the database is 20238-08-01 (eg it looks the or= iginal user did a keying error and put the month into the year field), this= gets returned by the ODBC driver as 2023-02-29. The client application th= en 'fails' in some way as this is not a valid date. We've been a bit busy manually trying to find and change invalid dates toda= y to fully work it through but I did a simple test using Excel as the ODBC = client to prove what was happening. If the first 4 digits of a 5 digit yea= r date happen to be a leap year, all is well. But if they are not a leap y= ear, something bad happens. Having a quick look at the driver code, from what I can see the issue is in= copy_and_convert_field I assume the parsing of the postgresql date using the scanf in the lines case PG_TYPE_DATE: sscanf(value, "%4d-%2d-%2d"= , &std_time.y, &std_time.m, &std_time.d); Reads the 1st 4 digits of the year but the rest just fails and m and d are = left set to zero. Then later on the code does = /* = * Initialize date in case conversion destination = * expects date part from this source time data. = * A value may be partially set here, so do some = * sanity checks on the existing values before = * setting them. = */ = tim =3D SC_get_localtime(stmt); = if (std_time.m =3D=3D 0) = std_time.m =3D tim->tm_mon + 1; = if (std_time.d =3D=3D 0) = std_time.d =3D tim->tm_mday; = if (std_time.y =3D=3D 0) = std_time.y =3D tim->tm_year + 1900; Which sets any date fields which are zero to their values from 'today'. For us, it would have been better if the ODBC driver returned either an err= or of some sort telling the user about the invalid date, or returned some d= ate which was 'valid' but logically represents an 'out of range' value such= as 9999-12-31 rather than return a date that doesn't actually exist. With= the current behaviour, some applications seemed to show an 'Error' in the = field while others have just crashed with an exception when they come acros= s the 'invalid' date being returned. For the rest of the days of the year, the user gets given a 'valid' (althou= gh somewhat random) date and just assumes that is the data in the database!= They have no way to see the 'real' data to know otherwise. 29 Feb 2020 was a Saturday and so I guess very few users were querying the = database and we didn't notice the issue. 29 Feb 2016 is so long ago no one= around here remembers if it was mayhem - but 29 Feb 2024 has been busy for= us! --_000_DU0P191MB2082B40B00EE9A8CEE50F16C865F2DU0P191MB2082EURP_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable

We’ve had an issue pop up= today due to the leap day that I wanted to let you know about.<= /span>

 

If a postgresql database table = contains a date with more than 4 digits in the year, it appears that the po= stgresql ODBC driver does something weird:

- It takes the first 4 digits o= f the year

- It then uses todays day and m= onth

 

It then returns this date as th= e value of the column.  The client software then tries to interpret th= is date into its native date type which, when the current date is the 29th Feb fails 75% of the time with a data conversion exception due to the resulting date not existing.

 

For example, if the date in the= database is 20238-08-01 (eg it looks the original user did a keying error = and put the month into the year field), this gets returned by the ODBC driv= er as 2023-02-29.  The client application then ‘fails’ in some way as this is not a valid date.

 

We’ve been a bit busy man= ually trying to find and change invalid dates today to fully work it throug= h but I did a simple test using Excel as the ODBC client to prove what was = happening.  If the first 4 digits of a 5 digit year date happen to be a leap year, all is well.  But if they are not= a leap year, something bad happens.

 

Having a quick look at the driv= er code, from what I can see the issue is in copy_and_convert_field

 

I assume the parsing of the pos= tgresql date using the scanf in the lines

 

     &= nbsp;           &nbs= p;            &= nbsp; case PG_TYPE_DATE:

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;     sscanf(value, "%4d-%2d-%2d", &std_= time.y, &std_time.m, &std_time.d);

 

Reads the 1st 4 digi= ts of the year but the rest just fails and m and d are left set to zero.

 

Then later on the code does

 

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            /*

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            * Init= ialize date in case conversion destination

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            * expe= cts date part from this source time data.

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            * A va= lue may be partially set here, so do some

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            * sani= ty checks on the existing values before

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            * sett= ing them.

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            */

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            tim = =3D SC_get_localtime(stmt);

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            if (st= d_time.m =3D=3D 0)

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;   std_time.m =3D tim->tm_mon + 1;

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            if (st= d_time.d =3D=3D 0)

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;   std_time.d =3D tim->tm_mday;

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            if (st= d_time.y =3D=3D 0)

     &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;   std_time.y =3D tim->tm_year + 1900;

 

Which sets any date fields whic= h are zero to their values from ‘today’.

 

For us, it would have been bett= er if the ODBC driver returned either an error of some sort telling the use= r about the invalid date, or returned some date which was ‘valid̵= 7; but logically represents an ‘out of range’ value such as 9999-12-31 rather than return a date that doesn’t actually e= xist.  With the current behaviour, some applications seemed to show an= ‘Error’ in the field while others have just crashed with an ex= ception when they come across the ‘invalid’ date being returned.

 

For the rest of the days of the= year, the user gets given a ‘valid’ (although somewhat random)= date and just assumes that is the data in the database!  They have no= way to see the ‘real’ data to know otherwise.

 

29 Feb 2020 was a Saturday and = so I guess very few users were querying the database and we didn’t no= tice the issue.  29 Feb 2016 is so long ago no one around here remembe= rs if it was mayhem – but 29 Feb 2024 has been busy for us!

--_000_DU0P191MB2082B40B00EE9A8CEE50F16C865F2DU0P191MB2082EURP_--