When trying to parse a Date with DateTime::createFromFormat
PHP will not recognize the timezone.
Example:
$t = new \DateTime();
echo $t->format('Y-m-dTH:i:s');
will output
2012-01-24MSK16:53:52
Now when I try to parse that string from the same format
var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));
I get
bool(false)
When I do not put the Timezone into the string, it works
$t = new \DateTime();
echo $t->format('Y-m-dH:i:s');
will give
2012-01-2417:17:24
and parsing that
var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', "2012-01-2417:17:24"));
will give
object(DateTime)#3 (3) {
["date"]=>
string(19) "2012-01-24 17:17:24"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Moscow"
}
Tested on
Problem appears just if we are take care about timezone. Is it a bug? Or what I do wrong? Thank you in advance!
It looks like a bug (or at least an undocumented limitation) with PHP... If we try the 4 possible whitespace permutations:
var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d T H:i:s', '2012-01-24 MSK 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d TH:i:s', '2012-01-24 MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dT H:i:s', '2012-01-24MSK 16:53:52'));
We get (tested PHP 5.3, 5.4rc6 and Trunk):
bool(false)
object(DateTime)#2 (3) {
["date"]=>
string(19) "2012-01-24 16:53:52"
["timezone_type"]=>
int(2)
["timezone"]=>
string(3) "MSK"
}
bool(false)
object(DateTime)#3 (3) {
["date"]=>
string(19) "2012-01-24 16:53:52"
["timezone_type"]=>
int(2)
["timezone"]=>
string(3) "MSK"
}
So that seems to point that the timezone identifier and/or hour are sensitive to whitespace... Testing further:
var_dump(\DateTime::createFromFormat('Y-m-d H:i:s', '2012-01-24 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', '2012-01-2416:53:52'));
Yields the proper results. And:
var_dump(\DateTime::createFromFormat('TY-m-d', 'MSK2012-01-24'));
var_dump(\DateTime::createFromFormat('T Y-m-d', 'MSK 2012-01-24'));
Yields:
bool(false)
object(DateTime)#4 (3) {
["date"]=>
string(19) "2012-01-24 01:49:26"
["timezone_type"]=>
int(2)
["timezone"]=>
string(3) "MSK"
}
So yes, it does appear that the timezone specifier is sensitive to trailing whitespace...
If we look at parse_date.c timelib_parse_from_format()
on line 25075, we can see that all 4 timezone formats are parsed the same way! That means there is no difference at all between the format identifiers for parsing, and therefore for parsing they are interchangable.
That alone seems like enough of a bug (or lack of a feature) to go on. But, let's see what happens in timelib_get_zone()
which is called when you use a timezone identifier. Well, looking on, we can see that we call timelib_lookup_zone()
when it's not GMT or a time offset.
And there we found the bug. On line 768 of timelib_lookup_zone
, we can see that it will consume the entire input string up to one of either \0
(null), )
or a space:
while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') {
++*ptr;
}
With respect to fixing it, that's a little more tricky. To just fix this issue, would require re-implementing the format parsers for each timezone. For the T
parser, this is easy, since it's always a 3 letter string. But for the others, it's a little more interesting, since there are variable letters, and as such whitespace sensitivity may be an issue.
So in short, I would suggest just adding a trailing white-space to your timezone identifiers and being done with it...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With