I'm using the following format Y-m-d\TH:i:s.v\Z to follow the JavaScript toISOString implementation (2011-10-05T14:48:00.000Z).
Everything works fine if I have a DateTime and I want to format it, however I cannot parse a string that uses this format.
$format = 'Y-m-d\TH:i:s.v\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format,$stringDateTime));
I'm using PHP 7 and I have tested the code above with PHP 7.0,7.1 and 7.2. The return that I expect in line 3 is a DateTime class, however I'm getting a false due to there is a parse problem.
I hope someone can clarify this behavior.
Thanks
Datetime will handle it fine, you won't need to create from format.
<?php
$format = 'Y-m-d\TH:i:s.v\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create($stringDateTime));
https://3v4l.org/phLE1
Result:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:07:30.005000"
["timezone_type"]=>
int(2)
["timezone"]=>
string(1) "Z"
}
This also works:
<?php
$format = 'Y-m-d\TH:i:s.u\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format, $stringDateTime));
$format = \DateTime::ISO8601;
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format, $stringDateTime));
https://3v4l.org/FcUqe
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:15:10.011717"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:15:10.000000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+01:00"
}
Related
Awkward problem -> I'm trying to get current date&time in ISO 8601 format (like this: 2022-02-11 12:30:02.846108).
When I run $time = new Time('now', 'Europe/Amsterdam') in CI4, $time returns this:
object(CodeIgniter\I18n\Time)#79 (6)
{ ["timezone":protected]=> object(DateTimeZone)#80 (2)
{ ["timezone_type"]=> int(3)
["timezone"]=> string(16) "Europe/Amsterdam"
}
["locale":protected]=> string(2) "en"
["toStringFormat":protected]=> string(19) "yyyy-MM-dd HH:mm:ss"
["date"]=> string(26) "2022-02-11 12:30:02.846108"
["timezone_type"]=> int(3)
["timezone"]=> string(16) "Europe/Amsterdam"
}
but when i try to get $time->date returns NULL.
Any ideea how to access date string in order to get the current time with microseconds?
Found out there is no ->date attribute in the DateTime object, which is why $time->date returns NULL.
The proper way to get the date with microseconds is:
$time->format('Y-m-d\TH:i:s.u')
Please let me construct a statement to calculate the number of days between two variables that have the format: 20211024. This is of course the year, then month, then day in a single eight digit variable.
By using the DateTime class?
$d = new DateTime('20211024');
var_dump($d);
$d2 = new DateTime('20211014');
var_dump($d2);
echo $d->diff($d2)->format('%R%a days');
That example code gives the output:
object(DateTime)#7 (3) {
["date"]=>
string(26) "2021-10-24 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
object(DateTime)#8 (3) {
["date"]=>
string(26) "2021-10-14 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
-10 days
Example fiddle
I need to create one date using only month and year.
I'm using this code:
$mData="1 2003";
$mDate=DateTime::createFromFormat("n Y", $mData);
var_dump($mDate);
Output in this case is fine:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2003-01-10 15:43:33.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
Now I try with one month that not exists:
$mData="21 2003";
$mDate=\DateTime::createFromFormat("n Y", $mData);
var_dump($mDate);
Output is one date of september 2004!:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2004-09-10 15:45:26.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
Why in this case $mDate is not false o any error occours?
It's not possible to create one valid DateTime object in this way controlling erroneus dates.
In my scenario I can't to change the format "n Y" by another format, then I need to achieve this controlling errors? It's possible?
Now I try with one month that not exists 21
21 = 12 + 9 = 1y + 9m
Which is exactly what you are getting
string(26) "2004-09-10 15:45:26.000000"
As the other answer points out, the behavior is the behavior, so you can check yourself:
$mData = "21 2003";
$a = explode(' ', $mData);
var_dump(
checkdate($a[0], 1, $a[1])
);
You can check if the year from the DateTime Object is the same as the year of the input:
$mData = "13 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
$error = ($mDate === false OR strpos($mData, $mDate->format('Y')) < 2) ;
var_dump($error); //bool(true)
or you use date_get_last_errors(). This function provides a warning that you can evaluate.
$mData = "21 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
var_dump(date_get_last_errors());
output:
array(4) {
["warning_count"]=>
int(1)
["warnings"]=>
array(1) {
[7]=>
string(27) "The parsed date was invalid"
}
["error_count"]=>
int(0)
["errors"]=>
array(0) {
}
}
Note:
The format "!n Y" results in a date with day 1 and time 00:00.
$mData = "5 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
$error = ($mDate === false OR strpos($mData, $mDate->format('Y')) < 2) ;
var_dump($mDate,$error);
Output:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2003-05-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
bool(false)
I have problem with PHP DateDiff, i dont understand why each timezone returns different results, for example in this case Prague return 0 month, and US return 1 month.
What do this difference and how i return 1 month (instead 30 days, when i adding 1 month) as expected?
code Europe/Prague:
date_default_timezone_set("Europe/Prague");
$from = new \DateTimeImmutable('2016-09-01');
$to = $from->add(new \DateInterval('P1M'));
var_dump($from);
var_dump($to);
var_dump($from->diff($to)->m);
var_dump($from->diff($to)->d);
result Europe/Prague:
object(DateTimeImmutable)#1 (3) {
["date"]=>
string(26) "2016-09-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Prague"
}
object(DateTimeImmutable)#3 (3) {
["date"]=>
string(26) "2016-10-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Prague"
}
int(0)
int(30)
--
code US/Pacific:
date_default_timezone_set("US/Pacific");
$from = new \DateTimeImmutable('2016-09-01');
$to = $from->add(new \DateInterval('P1M'));
var_dump($from);
var_dump($to);
var_dump($from->diff($to)->m);
var_dump($from->diff($to)->d);
result US/Pacific:
object(DateTimeImmutable)#2 (3) {
["date"]=>
string(26) "2016-09-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
object(DateTimeImmutable)#4 (3) {
["date"]=>
string(26) "2016-10-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(10) "US/Pacific"
}
int(1)
int(0)
This is indeed a small bug in PHP DateTime class.
You must use the UTC timezone and set the desired timezone after the calculation :
date_default_timezone_set('UTC');
$europePrag = new DateTimeZone('Europe/Prague');
$usPacific = new DateTimeZone('US/Pacific');
$from = new \DateTimeImmutable('2016-11-01');
$to = $from->add(new \DateInterval('P1M'));
$from->setTimezone($europePrag);
var_dump($from);
var_dump($to);
var_dump($from->diff($to)->m);
var_dump($from->diff($to)->d);
$from = new \DateTimeImmutable('2016-11-01');
$to = $from->add(new \DateInterval('P1M'));
$from->setTimezone($usPacific);
var_dump($from);
var_dump($to);
var_dump($from->diff($to)->m);
var_dump($from->diff($to)->d);
I think it is the behaviour described in this ticket:
https://bugs.php.net/bug.php?id=52480
So, yes it seems to be a bug in PHP.
So I'm trying to convert milliseconds to date in PHP and I thought the script I had was working fine but getting odd behaviour for a specific millisecond value (1425318722000).
I've checked this across a few websites and all come back with a valid value...
Monday, March 2, 2015 5:52:02 PM GMT
Mon Mar 02 2015 17:52:02
Mon Mar 02 2015 17:52:02 GMT+0000 (GMT)
Mon, 02 Mar 2015 17:52:02 GMT
Any idea why this occurs, is it a PHP bug perhaps?
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318721999/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:01"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722000/1000));"
bool(false)
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722001/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722002/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722003/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722004/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722005/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
It's the fact that you're using the 'U.u' mask, but the .u is lost from the value when the result is all 0s after the decimal for that division
for($ms = 1425318721999; $ms <= 1425318722001; ++$ms) {
var_dump(DateTime::createFromFormat('U.u', sprintf('%14.3f', $ms/1000)));
}
Will work, because you're using sprintf() to force those zeroes to be retained after the decimal point
for($ms = 1425318721999; $ms <= 1425318722001; ++$ms) {
var_dump(DateTime::createFromFormat('U', floor($ms/1000)));
}
would also work, but you'd lose the milliseconds precision
By way of some explanation:
public static DateTime DateTime::createFromFormat ( string $format , string $time [, DateTimeZone $timezone ] )
the createFromFormat() expects a string as the second argument, so PHP is loose casting the result of your division to a string, and a float value like 1425318722.000 will be cast to a string of "1425318722" with no decimal point or following zeroes, so it doesn't conform with the U.u mask which requires the decimal point and following digits