php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76770 'U' modifier in 'datetime::createFromFormat' adds seconds to other specifiers
Submitted: 2018-08-20 12:08 UTC Modified: 2020-12-23 15:49 UTC
Votes:2
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (100.0%)
From: bjoern dot fischer at dezem dot de Assigned: derick (profile)
Status: Closed Package: Date/time related
PHP Version: Irrelevant OS: Linux
Private report: No CVE-ID: None
 [2018-08-20 12:08 UTC] bjoern dot fischer at dezem dot de
Description:
------------
This problem apparently exists on all PHP versions where 'datetime' is present.

The problem can be reproduced here: https://3v4l.org/21PWU

The given example should create the time-stamp '3600' but the actual result is '7200'.

It appears as if the value of 'U' is just added to other date/time information.
However since 'U' represents a Unix-time-stamp, it itself fully specifies the time. It should not be changed if other format specifiers are present.


Test script:
---------------
<?php
var_dump(datetime::createFromFormat('!U H', '3600 01')->getTimestamp());

Expected result:
----------------
Using 'U' with 'datetime::createFromFormat' should result in a datetime object that returns the value for 'U' as a timestamp.

Actual result:
--------------
Using 'U' with 'datetime::createFromFormat' adds the value for 'U' and other date/time components together, resulting in incorrect time-stamps.

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-08-20 12:35 UTC] cmb@php.net
-Package: *General Issues +Package: Date/time related
 [2018-08-20 13:53 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2018-08-20 13:53 UTC] requinix@php.net
What should this return (given Aug 20 is a Monday):

DateTime::createFromFormat("!Y-m-d H:i:s D", "2018-08-20 12:34:56 Tuesday")
 [2018-08-21 07:15 UTC] bjoern dot fischer at dezem dot de
Hello requinix.

I don't seem to understand your question. The code you posted has no 'U' modifier in it and the reported bug only appears when using that modifier.
 [2018-08-21 08:50 UTC] requinix@php.net
-Status: Feedback +Status: Open
 [2018-08-21 08:50 UTC] requinix@php.net
I know, but I still want to know your opinion. Because I would argue that using 'U' or using a full 'Y-m-d H:i:s' should both work the same way when it comes to something that "fully specifies the time".

  DateTime::createFromFormat("!Y-m-d H:i:s D", "2018-08-20 12:34:56 Tuesday")
becomes either 8-20 (Monday) or 8-21 (Tuesday), depending. If it's the former then we've established a consistent behavior and I can understand it. If it's the latter then I think that's inconsistent and it implies 'U' is something unique and magical.

Either way I don't think we can change this behavior, if only for the simple reason that changing 'U' (at least) to work like this would break any existing code that wants to do something like
  DateTime::createFromFormat("!U D", "{$timestamp} Tuesday")
which would, hypothetically, be there to start with one timestamp and then deliberately modify it - much like how strtotime() is often used.
 [2018-08-21 10:13 UTC] bjoern dot fischer at dezem dot de
Ah. Now I get your concern.

I think this is a separate problem.
In my opinion, your example should just result in an error as the provided date/time-string is inconsistent. (I'm actually currently implementing a wrapper around 'datetime' that  does this.)
However preferring the first or the last of those two redundant specifiers would both be understandable to me.
I don't really understand yet why the former should be preferred.

In the issue I describe, something different happens.
There we have a redundant time format where the specified date/time-string is actually consistent.
But instead  of just having the components accepted as consistent, they are added together.

I think the use case that you describe should not be the point of 'datetime::createFromFormat()'. We have 'datetime::modify()' for that.

Also this would be inconsistent with the rest of the behaviour of 'datetime::createFromFormat()'.
For example:
'var_dump(datetime::createFromFormat('!d j', '02 2')->getTimestamp());'
currently results in the time-stamp '86400'. By the reasoning you propose it should result in the time-stamp '172800'.
 [2018-08-21 10:37 UTC] requinix@php.net
Okay, so after playing with it some more, it looks like 'U' is actually magical like I suggested it should not be.
https://3v4l.org/CCPrd

With 'U', additional date parts are *added* to the timestamp. With other specifiers, date parts are *merged* with latter values overriding earlier values.

So I'm thinking either
a) 'U' should be fixed to not do that and to act like everything else, possibly with the last errors set, or
b) createFromFormat should reject the string entirely, and not just with 'U' but with other inconsistent strings

If it can't be changed then at least it needs to be documented.
 [2019-02-22 23:05 UTC] petk@php.net
The following pull request has been associated:

Patch Name: Fix #76770: Unix time parsed as non relative.
On GitHub:  https://github.com/php/php-src/pull/3514
Patch:      https://github.com/php/php-src/pull/3514.patch
 [2020-01-20 17:34 UTC] girgias@php.net
-Assigned To: +Assigned To: derick
 [2020-12-23 15:49 UTC] cmb@php.net
-Status: Assigned +Status: Closed
 [2020-12-23 15:49 UTC] cmb@php.net
This issue is fixed with the latest timelib, and as such as of PHP
8.0.0.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 04:01:31 2024 UTC