php - Issue with DateTime CreateFromFormat using RFC3339
I have this date-time stamp:
"2021-06-08T13:09:00.9796129Z"
And I cannot convert it in to a DateTime object using CreateFromFormat. I am using a JanePHP Normaliser so would prefer to try and solve this strictly using CreateFromFormat. I have tried the following:
$options = [
\DateTimeInterface::ATOM,
\DateTimeInterface::COOKIE,
\DateTimeInterface::ISO8601,
\DateTimeInterface::RFC822,
\DateTimeInterface::RFC850,
\DateTimeInterface::RFC1036,
\DateTimeInterface::RFC1123,
\DateTimeInterface::RFC7231,
\DateTimeInterface::RFC2822,
\DateTimeInterface::RFC3339,
\DateTimeInterface::RFC3339_EXTENDED,
\DateTimeInterface::RSS,
\DateTimeInterface::W3C,
'Y-m-dTH:i:s.uP',
'Y-m-dTH:i:s.P',
'Y-m-dTH:i:s.vP',
];
foreach ($options as $name) {
var_dump(\DateTime::createFromFormat($name, "2021-06-08T13:09:00.9796129Z"));
}
All result in:
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
What is the correct format?
Answer
Solution:
You have a simple problem, and a more complex problem.
The simple problem is that to match a literal T, you need to escape it with a backslash. That ought to allow this pattern:
'Y-m-d\TH:i:s.uP'
(Year-month-day, literal T, hour:minute:second.microsecond, time zone)
The complex problem is that your timestamp has 7 decimal places in the seconds, giving a resolution of a tenth of a microsecond. That's why the u
specifier isn't matching:
u: Microseconds (up to six digits)
A workaround would be to use the ? specifier which matches any single byte:
'Y-m-d\TH:i:s.u?P'
(Year-month-day, literal T, hour:minute:second.microsecond, ignore a byte for the extra digit, time zone)
var_dump(\DateTime::createFromFormat('Y-m-d\TH:i:s.u?P', "2021-06-08T13:09:00.9796129Z"));
# object(DateTime)#1 (3) {
# ["date"]=>
# string(26) "2021-06-08 13:09:00.979612"
# ["timezone_type"]=>
# int(2)
# ["timezone"]=>
# string(1) "Z"
# }
Answer
Solution:
You're not escaping the T, so it's attempting to use that as a placeholder (Timezone abbreviation). The correct format would be
'Y-m-d\TH:i:s.u\Z'
Source