php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81565 BC break: date parsing fails when provided with timezones including seconds
Submitted: 2021-10-29 14:08 UTC Modified: 2022-05-13 15:37 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: andrea dot sprega at slope dot it Assigned:
Status: Closed Package: Date/time related
PHP Version: 8.0.12 OS: Linux (The only I could try)
Private report: No CVE-ID: None
 [2021-10-29 14:08 UTC] andrea dot sprega at slope dot it
Description:
------------
Past dates in some timezones used to have "weird" timezones that included seconds. Example for Europe/Rome: https://nodatime.org/tzvalidate/generate?version=2019a&zone=Europe/Rome

Starting from PHP 8.0.10, parsing for dates with timezones including seconds started to fail -- DateTime::createFromFormat started returning false instead of a DateTime, even if it previously ignored the fractional timezone (which is fine, assuming seconds are not supported by PHP timezones).

This is a BC break for all applications that work with this kind of dates.

We believe this could be a side effect of one of these issues:

https://bugs.php.net/bug.php?id=78984
https://bugs.php.net/bug.php?id=79580

NOTE: we found out about this because of an incorrect, non validated input of a user that wrote "21" instead of "2021" as year, thus producing this weird date that ended up in our database. Then, when reading back that date on a connection with timezone set to Europe/Rome, the database performs the conversion and correctly adds the fractional timezone valid for year 21 AD.

We currently worked around the issue by manually removing seconds from the timezone (which basically restored the behavior up to 8.0.9).


Test script:
---------------
<?php

var_export(
    \DateTime::createFromFormat(
        'Y-m-d H:i:sO',
        '0021-08-21 00:00:00+00:49:56'
    )
);


// NOTE: any date before 1893-10-31 23:00:00Z (with fractional timezone, as you can see from the link in the description) would reproduce the issue

Expected result:
----------------
DateTime::__set_state(array(
   'date' => '0021-08-21 00:00:56.000000',
   'timezone_type' => 1,
   'timezone' => '+00:00',
))

Actual result:
--------------
false

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-10-29 15:13 UTC] cmb@php.net
For reference: <https://3v4l.org/BeEcm>.
 [2021-11-02 11:54 UTC] alec at alec dot pl
According to the documentation +00:49:56 is not a correct timezone. So, the behavior sounds right no me.

DateTime::getLastErrors() in this case contains "The timezone could not be found in the database" error.
 [2021-11-02 12:37 UTC] heiglandreas@php.net
@alec

> According to the documentation +00:49:56 is not a correct timezone.

Do you have a link to that documentation?
 [2021-11-02 13:28 UTC] ximarx at gmail dot com
According to https://www.iana.org/time-zones tzdata, basically ~any timezone for an "old enough" date in the past is assigned to a sub-minute offset value

E.g.:

```
America/Los_Angeles
Initially:           -07:52:58 standard LMT
1883-11-18 20:00:00Z -08:00:00 standard PST
```

```
America/Los_Angeles
Initially:           -07:52:58 standard LMT
1883-11-18 20:00:00Z -08:00:00 standard PST
```

```
Europe/London
Initially:           -00:01:15 standard LMT
1847-12-01 00:01:15Z +00:00:00 standard GMT
```

As reference: GNU date (coreutils) using tzdata 2021e


```
$ dpkg -s tzdata | grep -i version
Version: 2021e-0ubuntu0.20.04

$ TZ="Europe/Rome" date -d"Sat, 28 Jul 1838 17:12:33 +0000" +"%F %T %:::z"
1838-07-28 18:02:29 +00:49:56

$ TZ="Europe/London" date -d"Sat, 28 Jul 1838 17:12:33 +0000" +"%F %T %:::z"
1838-07-28 17:11:18 -00:01:15
```
 [2021-11-02 13:29 UTC] alec at alec dot pl
https://www.php.net/manual/en/datetime.createfromformat.php where the timezone format is described.
 [2021-11-12 15:46 UTC] antonino dot spampinato86 at gmail dot com
1) Format "O" Difference from Greenwich Mean Time (GMT) without the colon between hours and minutes.
2) Problems with the transition period (2)a also this bug #80963 getTransitions does not restore the correct values ​​except the date). 2)b example timezone America/Toronto progress of +00:15:32 in php after 7.3.1 https://3v4l.org/CY4F7 related to bug #81562
3) You must first solve problem number two and create a new format that accepts hours, minutes, seconds with or without a semicolon otherwise the behavior of php 8.0.10 is correct (read DateTime::format for "O"). The ticket is a feature request, this is my thought since if it does not exist you cannot merge, if php creates code without modifying the format historical. @derick behavior we go to the correct.

For Europe/Rome read RMT timezone (49*60) + 56.
 [2021-11-12 15:54 UTC] andrea dot sprega at slope dot it
But if the same code used to work (even though by approximating to a timezone without seconds) up to PHP 8.0.9, and it stopped in 8.0.10, how can this not be considered a BC break?

The feature request would be to handle timezones with seconds, but TBH I don't think this is of any interest to most users (at least not for me).

What it is reasonable to expect, in my opinion, is that PHP handles gracefully this kind of timezones, given that they are technically and syntactically correct.
 [2021-11-12 16:15 UTC] antonino dot spampinato86 at gmail dot com
If it is a closed project, the programmer chooses.
I agree that if the "O" format can be expanded as input +004956 while output with hours and minutes without semicolons.
the behavior prior to 8.0.10 is not correct, as I could not find it in the php documents you have to decide how to expand the date "O" and this choice is made by the php team. Otherwise, without any reference, can a user tell why the input is different from the output?
I'm normal user :)
 [2021-11-12 18:08 UTC] antonino dot spampinato86 at gmail dot com
$date =
    \DateTime::createFromFormat(
        'Y-m-d H:i:sO',
        '0021-08-21 00:00:00+00:49:56'
    );
var_dump($date); //timezone UTC or +00:00?. Error Real timezone is +2996

From php 8.0.10 DateTimeZone relative to fix bug #81097 (maybe this BC).

DateTime takes no seconds but uses the type +hh:mm for the time zone bug #70701
 [2022-05-13 15:37 UTC] derick@php.net
-Status: Open +Status: Wont fix
 [2022-05-13 15:37 UTC] derick@php.net
I sort of see how this can be a BC break, but @cmb's example shows that it actually never worked:

https://3v4l.org/BeEcm

Instead of truncating the seconds in the timezone to 00:49, it cut it to 00:00.

Although timelib does internally support sub-minute timezone offsets, PHP's data structures do not. It did however not support parsing this information, which I have now added: https://github.com/derickr/timelib/commit/2788ebbedfd72bc5fe2d262893e7bf40ec1f5818

I don't really believe that silently truncating data on the PHP side is a good thing either. I am going to close this issue, and if you have a better solution, please open a new one at https://github.com/php/php-src/issues.
 [2022-05-20 12:25 UTC] git@php.net
Automatic comment on behalf of derickr
Revision: https://github.com/php/php-src/commit/008016b536fec6f98db35a74f10f97152122a365
Log: Fixed bug #81565 (date parsing fails when provided with timezones including seconds)
 [2022-05-20 12:25 UTC] git@php.net
-Status: Wont fix +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC