Skip to content

Instantly share code, notes, and snippets.

@thinkt4nk
Forked from graste/datetime.php
Created August 16, 2018 23:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thinkt4nk/5c82171535afd9d042ba0437dc50f22c to your computer and use it in GitHub Desktop.
Save thinkt4nk/5c82171535afd9d042ba0437dc50f22c to your computer and use it in GitHub Desktop.
PHP DateTime class – parsing and formatting ISO8601 dates with or w/o fractions of a second
<?php
echo 'default locale: ' . \Locale::getDefault();
echo PHP_EOL;
echo 'default timezone: ' . \date_default_timezone_get();
echo PHP_EOL;
// see http://tools.ietf.org/html/rfc3339#section-5.8 for example datetimes
// bug report on missing fractions support: https://bugs.php.net/bug.php?id=51950
// feature request for fractions support in constructor: https://bugs.php.net/bug.php?id=49779
$dt2 = \DateTime::createFromFormat('Y-m-d\TH:m:i.uO', '2012-10-17');
var_dump($dt2); // false
$dt2 = new \DateTime('2012-10-17');
echo '2012-10-17 formatted => ' . $dt2->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
$dt3 = \DateTime::createFromFormat('Y-m-d\TH:m:i.uO', '1990-12-31T23:59:60Z'); // leap second
var_dump($dt3); // false
$dt3 = new \DateTime('1990-12-31T23:59:60Z');
echo '1990-12-31T23:59:60Z formatted => ' . $dt3->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
$dt4 = \DateTime::createFromFormat(\DateTime::ISO8601, '2004-02-13T15:19:21+00:00');
echo '2004-02-13T15:19:21+00:00 formatted => ' . $dt4->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
$dt5 = \DateTime::createFromFormat('Y-m-d\TH:m:i.uO', '1985-04-12T23:20:50.52Z');
echo '1985-04-12T23:20:50.52Z formatted => ' . $dt5->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
echo '\DateTime::createFromFormat(DateTime::ISO8601, "1985-04-12T23:20:50.52Z") => ';
$datetime = \DateTime::createFromFormat(\DateTime::ISO8601, '1985-04-12T23:20:50.52Z');
var_dump($datetime);
echo 'new \DateTime("1985-04-12T23:20:50.52Z") => ';
$datetime = new \DateTime('1985-04-12T23:20:50.52Z');
var_dump($datetime);
echo '1985-04-12T23:20:50.52Z formatted (P) => ' . $datetime->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
//$datetime = \DateTime::createFromFormat('c', '1985-04-12T23:20:50.52Z'); // fails
$datetime = new \DateTime('1985-04-12T23:20:50.52Z');
var_dump($datetime);
$datetimez = clone $datetime;
$datetime->setTimeZone(new \DateTimeZone('Zulu'));
$datetime->setTimeZone(new \DateTimeZone('Etc/UTC'));
$datetime->setTimeZone(new \DateTimeZone('UTC'));
echo '1985-04-12T23:20:50.52Z clone Z formatted => ' . $datetime->format('Y-m-d\TH:i:s.u\Z');
echo PHP_EOL;
echo '1985-04-12T23:20:50.52Z clone Z formatted => ' . $datetime->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
$iso8601_p = sprintf(
"%s%03d%s",
$datetime->format("Y-m-d\TH:i:s\."),
floor($datetime->format("u") / 1000),
$datetime->format("P")
);
echo '1985-04-12T23:20:50.52Z clone custom formatted P => ' . $iso8601_p;
echo PHP_EOL;
$iso8601_z = sprintf(
"%s%03dZ",
$datetime->format("Y-m-d\TH:i:s\."),
floor($datetime->format("u") / 1000)
);
echo '1985-04-12T23:20:50.52Z clone custom formatted Z => ' . $iso8601_z;
echo PHP_EOL;
echo '\DateTime::diff() with fractions of a second granularity is not possible…';
echo PHP_EOL;
echo "Propably need to use format('u') and compare those when treated as integer…";
echo PHP_EOL;
echo 'NOW with fractions (P): ' . \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)))->format('Y-m-d\TH:i:s.uP');
echo PHP_EOL;
echo 'NOW with fractions (O): ' . \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)))->format('Y-m-d\TH:i:s.uO');
echo PHP_EOL;
$ php -v
PHP 5.5.9-1ubuntu4.5 (cli) (built: Oct 29 2014 11:59:10)
$ php datetime.php 
default locale: en_US
default timezone: Europe/Berlin
bool(false)
2012-10-17 formatted => 2012-10-17T00:00:00.000000+02:00
bool(false)
1990-12-31T23:59:60Z formatted => 1991-01-01T00:00:00.000000+00:00
2004-02-13T15:19:21+00:00 formatted => 2004-02-13T15:19:21.000000+00:00
1985-04-12T23:20:50.52Z formatted => 1986-08-12T23:50:00.520000+00:00
\DateTime::createFromFormat(DateTime::ISO8601, "1985-04-12T23:20:50.52Z") => bool(false)
new \DateTime("1985-04-12T23:20:50.52Z") => object(DateTime)#8 (3) {
  ["date"]=>
  string(19) "1985-04-12 23:20:50"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(1) "Z"
}
1985-04-12T23:20:50.52Z formatted (P) => 1985-04-12T23:20:50.520000+00:00
object(DateTime)#9 (3) {
  ["date"]=>
  string(19) "1985-04-12 23:20:50"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(1) "Z"
}
1985-04-12T23:20:50.52Z clone Z formatted => 1985-04-12T23:20:50.520000Z
1985-04-12T23:20:50.52Z clone Z formatted => 1985-04-12T23:20:50.520000+00:00
1985-04-12T23:20:50.52Z clone custom formatted P => 1985-04-12T23:20:50.520+00:00
1985-04-12T23:20:50.52Z clone custom formatted Z => 1985-04-12T23:20:50.520Z
\DateTime::diff() with fractions of a second granularity is not possible…
Propably need to use format('u') and compare those when treated as integer…
NOW with fractions (P): 2015-01-22T12:49:24.653245+00:00
NOW with fractions (O): 2015-01-22T12:49:24.653462+0000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment