php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #55240 DateTime::createFromFormat with format 'd.m.Y Gi' returns wrong date
Submitted: 2011-07-19 11:11 UTC Modified: 2021-09-28 09:26 UTC
Votes:8
Avg. Score:3.8 ± 1.3
Reproduced:6 of 6 (100.0%)
Same Version:3 (50.0%)
Same OS:1 (16.7%)
From: m dot strucken at binserv dot de Assigned: cmb (profile)
Status: Closed Package: Date/time related
PHP Version: 5.3.6 OS: Windows Server 2008 R2
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: m dot strucken at binserv dot de
New email:
PHP Version: OS:

 

 [2011-07-19 11:11 UTC] m dot strucken at binserv dot de
Description:
------------
Having a date without a delimiter between hour and minute and the hour without leading zero, the returned date from DateTime::createFromFormat() is incorrect

Test script:
---------------
$dt = DateTime::createFromFormat( 'd.m.Y Gi', '11.11.2009 800' );
echo $dt->format( 'd.m.Y Gi' );

Expected result:
----------------
11.11.2009 800

Actual result:
--------------
14.11.2009 800

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-07-19 18:33 UTC] felipe@php.net
-Package: Unknown/Other Function +Package: Date/time related
 [2011-08-03 20:09 UTC] derick@php.net
-Assigned To: +Assigned To: derick
 [2011-11-26 16:40 UTC] derick@php.net
Hi!

I've had a look at this, and now I can tell you what happens.
Without the delimiter, the 800 gets parsed as 80 hours, 0 minutes.
If you add 80 hours to  11.11.2009, that means 3 days, 8 hours, you get 14.11.2009, 8am.

If you call DateTime::getLastError, you see it shows a warning:

derick@whisky:~$ cat /tmp/test.php 
<?php
$dt = DateTime::createFromFormat( 'd.m.Y Gi', '11.11.2009 800' );
var_dump($dt);
var_dump(DateTime::getLastErrors());
echo $dt->format( 'd.m.Y G i' );
?>

derick@whisky:~$ php /tmp/test.php 
class DateTime#1 (3) {
  public $date =>  string(19) "2009-11-14 08:00:00"
  public $timezone_type =>  int(3)
  public $timezone =>  string(13) "Europe/London"
}
array(4) {
  'warning_count' =>
  int(1)
  'warnings' =>
  array(1) {
    [14] =>
    string(27) "The parsed time was invalid"
  }
  'error_count' =>
  int(0)
  'errors' =>
  array(0) {
  }
}
14.11.2009 8 00
derick@whisky:~$ 

The parser for "G" parses up to 2 characters, and it doesn't know how to stop if it encounters something too high. I'm looking at how I can changes this, but still not break BC in any form. I've changed the bug's status to FR now.

cheers,
Derick
 [2011-11-26 16:40 UTC] derick@php.net
-Type: Bug +Type: Feature/Change Request
 [2014-01-09 17:26 UTC] brian at brianhogg dot ca
This is similar to this example:

<?php
$date = DateTime::createFromFormat('MjY', 'Jan92014');
var_dump($date);
var_dump(DateTime::getLastErrors());

which outputs:

class DateTime#1 (3) {
  public $date =>
  string(19) "0014-04-02 18:24:29"
  public $timezone_type =>
  int(3)
  public $timezone =>
  string(13) "Europe/Zurich"
}
array(4) {
  'warning_count' =>
  int(1)
  'warnings' =>
  array(1) {
    [8] =>
    string(27) "The parsed date was invalid"
  }
  'error_count' =>
  int(0)
  'errors' =>
  array(0) {
  }
}

Technically you could know where to stop based on the fact that Y is 4 digits and M is 3 characters, but understand that parsing left-to-right makes this difficult.
 [2017-10-24 07:57 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: derick +Assigned To:
 [2021-09-28 09:26 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2021-09-28 09:26 UTC] cmb@php.net
As of PHP 5.3.9, this fails[1], and I think we can leave it at
that.

[1] <https://3v4l.org/XRpio>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 27 16:01:27 2024 UTC