php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62476 DateTime::createFromFormat z format incorrect wrt 29.02
Submitted: 2012-07-04 00:20 UTC Modified: 2016-07-28 17:27 UTC
Votes:18
Avg. Score:4.6 ± 0.7
Reproduced:16 of 16 (100.0%)
Same Version:5 (31.2%)
Same OS:2 (12.5%)
From: kaido at tradenet dot ee Assigned:
Status: Open Package: Date/time related
PHP Version: 5.4.4 OS: debian 2.6.32-5-amd64
Private report: No CVE-ID:
Have you experienced this issue?
Rate the importance of this bug to you:

 [2012-07-04 00:20 UTC] kaido at tradenet dot ee
Description:
------------
When creating DateTime object from string and using z (day of year) format option, 
the 29.02 of the leap year is missing. works ok in 5.3.5

Test script:
---------------
for ($d=55;$d<65;$d++) {
        $dt = DateTime::createFromFormat ('z.Y', $d.'.2012');
        $dd = $dt->format ('d.m.Y');
        echo "$d $dd\n";
}

29.02.2012 is clearly missing .. 

Expected result:
----------------
55 25.02.2012
56 26.02.2012
57 27.02.2012
58 28.02.2012
59 29.02.2012
60 01.03.2012
61 02.03.2012
62 03.03.2012
63 04.03.2012
64 05.03.2012

Actual result:
--------------
55 25.02.2012
56 26.02.2012
57 27.02.2012
58 28.02.2012
59 01.03.2012
60 02.03.2012
61 03.03.2012
62 04.03.2012
63 05.03.2012
64 06.03.2012

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-07-05 11:04 UTC] Sjon at hortensius dot net
I can confirm this, this is broken since 5.3.9

http://3v4l.org/1Z4W4
 [2012-07-05 19:13 UTC] kaido at tradenet dot ee
the bug was introduced in commit 4c9fad8b362a7d2b6a94b4961e4b2dc037b2766d to fix 
the bug #51994.

the problem is that in parse_date.c in timelib_parse_from_format() function, in 
case of the z-format option, the date is immidiately normalized, but at that 
point (if year format option happens to come _after_ the z - ie right from it) 
year is not yet set, and -99999 is used instead, which most probably is not a 
leap year :)

the obvious quick solution is to call timelib_do_normalize() only if year is  
set already.

doing so passes all test, too. even the one for #51994.

should the timelib_do_normalize() call be added to year option, too, if 
date/month are set at that point?


also, in timelib_do_normalize() there seems to be 3 checks like:

if (time->s != TIMELIB_UNSET) .. 

shouldn't 2nd and 3rd be "if (time->i != TIMELIB_UNSET)" and "if (time->h != 
TIMELIB_UNSET)" instead ?

(I did not dig deep enough, to be sure, though)
 [2015-02-03 19:40 UTC] kohenkatz at gmail dot com
Why is this still an issue 2.5 years later?

I see it in 5.5.12 on Ubuntu 14.10 and 5.6.5 on Windows Server 2012.
 [2015-03-10 09:14 UTC] info at giorgiosironi dot com
Possible workaround:

$ php -r 'echo DateTime::createFromFormat("z Y", "59 2016")->format("Y-m-d"), PHP_EOL;'
2016-03-01
$ php -r 'echo DateTime::createFromFormat("Y z", "2016 59")->format("Y-m-d"), PHP_EOL;'
2016-02-29
$ php -v
PHP 5.4.31-1+deb.sury.org~precise+1 (cli) (built: Jul 25 2014 07:04:32)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.2, Copyright (c) 1999-2013, by Zend Technologies

If it can be any helpful in Google searches for this bug, we encountered this when using MongoDB $dayOfYear aggregation option.
 [2016-07-28 17:27 UTC] cmb@php.net
-Package: Calendar related +Package: Date/time related
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Jul 23 02:01:35 2017 UTC