PHP DateTime with TimeZone to MongoDB\BSON\UTCDateTime - php

I need help with PHP DateTime with TimeZone converting to MongoDB\BSON\UTCDateTime.
If I have string "2015-10-20T04:02:00.608000+01:00" it gives me a DateTime
$date = DateTime::createFromFormat( 'Y-m-d\TH:i:s.uT', $string );
DateTime
date => "2015-10-20 04:02:00.608000"
timezone_type => 1
timezone => "+01:00"
If I convert it to MongoDB\BSON\UTCDateTime and convert back to PHP DateTime
$mDate = new \MongoDB\BSON\UTCDateTime( $date->format('U') * 1000 );
$mDate->toDateTime()->setTimeZone(new DateTimeZone('Europe/Bratislava'))
I will get a correct result 05:02
DateTime
date => "2015-10-20 05:02:00.000000"
timezone_type => 3
timezone => "Europe/Bratislava"
BUT if the input string has +02:00 TimeZone "2015-10-20T04:02:00.608000+02:00" and use the same approach the result is
DateTime
date => "2015-10-20 04:02:00.000000"
timezone_type => 3
timezone => "Europe/Bratislava"
Why is the second result 04:02 if I expect 06:02?

The response is correct. When you are adding a + timezone onto the timestamp, you are, in effect going East from UTC. You are not adding to the UTC time, you are actually subtracting from what the time is in UTC. This means that 2015-10-20T04:02:00.608000+01:00 is 3am UTC. 2015-10-20T04:02:00.608000+02:00 is 2am UTC. You can see this more easily if you keep going higher with your timezone offsets
$date = DateTime::createFromFormat( 'Y-m-d\TH:i:s.uT', "2015-10-20T04:02:00.608000+01:00");
$mDate = new \MongoDB\BSON\UTCDateTime( $date->format('U') * 1000 );
var_dump($date, $mDate->toDateTime());
object(DateTime)#1 (3) {
["date"]=>
string(26) "2015-10-20 04:02:00.608000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+01:00"
}
object(DateTime)#3 (3) {
["date"]=>
string(26) "2015-10-20 03:02:00.000000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
$date = DateTime::createFromFormat( 'Y-m-d\TH:i:s.uT', "2015-10-20T04:02:00.608000+02:00");
$mDate = new \MongoDB\BSON\UTCDateTime( $date->format('U') * 1000 );
var_dump($date, $mDate->toDateTime());
object(DateTime)#1 (3) {
["date"]=>
string(26) "2015-10-20 04:02:00.608000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+02:00"
}
object(DateTime)#3 (3) {
["date"]=>
string(26) "2015-10-20 02:02:00.000000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
MongoDB stores the UTC timestamp. When you are adding the Europe/Bratislava timezone, you are saying, "What time is in Bratislava for this UTC timestamp". For October (daylight savings time), it's a 1 hr difference.
On a side note. Try to never mix +XXXX and Unicode/Olson timezones (Europe/Bratislava). You will wind up with some very strange errors due to daylight savings time. If you need to record a user's local time to display back at some point, Create your DateTime objects with the optional 3rd parameter like:
$customerTz = 'Europe/Bratislava';
$date = DateTime::createFromFormat( 'Y-m-d\TH:i:s.u', $dateString, $customerTz);
Also check to see if you really need to create a DateTime at all, or just a new UTCDateTime directly with a timestamp and deal with the tz's in the display logic.

Related

How to get current DATE/TIME with microseconds in CI4?

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')

Incorrect time showing after converting to date format - PHP

Below is the time string I have,
'2019-12-30T15:42:33.891+11:00'
I tried to convert this to date format using below php code.
date('Y-m-d H:i:s',strtotime('2019-12-30T15:42:33.891+11:00'));
And i am getting 2019-12-30 10:12:33 as the output. It seems date getting correctly but time not.
How to display the time also correctly? Thanks in advance!
This date and time format relates to the "Zulu time" (UTC). UTC is refereed as Universal Time Coordinated. It is also known as “Z time” or “Zulu Time”.
You should change your timezone by some command like below code:
$date = new DateTime('2019-12-30T15:42:33.891+11:00', new DateTimeZone('UTC'));
echo $date->format('Y-m-d H:i:s');
Or, for having more tools you can use the Carbon library.
Your time string '2019-12-30T15:42:33.891+11:00' contains time zone information of +11:00.
With date() the date and time are converted into the local time zone of your server. For example, I get "2019-12-30 05:42:33" (Timezone Europe/Berlin).
You can set a different time zone with date_default_timezone_set() or use DateTime to output the time for a location with the time zone "+11:00".
echo date_create('2019-12-30T15:42:33.891+11:00')->format('Y-m-d H:i:s');
//2019-12-30 15:42:33
strtotime () returns an integer timestamp. The Iformation of the Timezone +11:00 are lost in the process, but are processed when the time stamp is determined.
The DateTime object always has a time zone.
echo '<pre>';
var_dump(date_create('2019-12-30T15:42:33.891+11:00'));
Output:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2019-12-30 15:42:33.891000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+11:00"
}
Note (Update):
When creating a DateTime object, the optional parameter for the time zone is only taken into account if the time string does not contain a time zone!
var_dump(new DateTime('2019-12-30T15:42:33.891 +11:00', new DateTimeZone('UTC')));
object(DateTime)#1 (3) {
["date"]=>
string(26) "2019-12-30 15:42:33.891000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+11:00"
}
//without +11:00
var_dump(new DateTime('2019-12-30T15:42:33.891', new DateTimeZone('UTC')));
object(DateTime)#1 (3) {
["date"]=>
string(26) "2019-12-30 15:42:33.891000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}

The function setTimezone changes the timezone but not the date

I am trying to change the TimeZone of my date from Europe/Berlin to UTC before storing in it into the DB.
When I use the setTimezone() method of the DateTime object, it changes the timezone property but not the date itself.
Example code :
$dt = new \DateTime();
var_dump($dt);
$dt->setTimezone(new \DateTimeZone('Indian/Comoro'));
var_dump($dt);
$dt->setTimezone(new \DateTimeZone('UTC'));
var_dump($dt);
And the result :
object(DateTime)#1479 (3) { ["date"]=> string(26) "2019-02-18 14:12:37.521579" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Europe/Berlin" }
object(DateTime)#1479 (3) { ["date"]=> string(26) "2019-02-18 14:12:37.521579" ["timezone_type"]=> int(3) ["timezone"]=> string(13) "Indian/Comoro" }
object(DateTime)#1479 (3) { ["date"]=> string(26) "2019-02-18 14:12:37.521579" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }
Berlin is UTC+1 and Comoro is UTC+3, but the date doesn't change.
I'm working with Symfony 4 on Vagrant.
This test is made inside of a controller
Is it possible that my Timezones are all set to +00 ?
What kind of tests could I implement to find the cause of this problem ?
UPDATE
This returns me an offset of 0 in my controller.
It returns 3600 with php CLI.
$tz = new \DateTimeZone('Europe/Berlin');
var_dump($tz->getOffset(new \DateTime('now', new \DateTimeZone('UTC'))));
The problem was from the tzdata package which worked well after updating.
I had to restart apache to make it work in my app.
The timestamp value represented by the DateTime object is not modified when you set the timezone using this method. Only the timezone, and thus the resulting display formatting, is affected.
Try this (assuming the date is set to Europe/Berlin timezone by default):
$dt = new \DateTime();
Pass through the timezone UTC:
$timezone = new \DateTimeZone('UTC');
we then need to get the offset.
$offset = $timezone->getOffset($dt);
lastly, modify the date using the offset:
$dt->modify($offset . 'seconds');

PHP Date after time change in Europe

This morning I ran unit tests and they failed.
Tests took offers from last 48 hours by calculating time with:
date('U', time() - 48 * 3600)
When I used:
(new DateTime('-48 hours'))->format('U')
it shown one hour difference.
May the reason be that on sunday in Poland time was moved one hour backwards
I presume your server runs with Europe/Warsaw as default time zone. PHP date/time calculations are often incorrect if they cross DST boundaries, as it's the case here. I suggest you do all maths in UTC and convert from/to local time as needed.
Please compare:
$warsaw = new DateTimeZone('Europe/Warsaw');
$utc = new DateTimeZone('UTC');
$start = new DateTime('2018-10-28 04:30:00', $warsaw);
$start->modify('-4 hours');
var_dump($start);
$start = new DateTime('2018-10-28 04:30:00', $warsaw);
$start->setTimezone($utc);
$start->modify('-4 hours');
$start->setTimezone($warsaw);
var_dump($start);
object(DateTime)#3 (3) {
["date"]=>
string(26) "2018-10-28 00:30:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Warsaw"
}
object(DateTime)#4 (3) {
["date"]=>
string(26) "2018-10-28 01:30:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Warsaw"
}
The Unix timestamp version of your code should be unaffected because a Unix timestamp is a fixed moment in time (thus doesn't switch with time zones).

Why convert Timestamp '2016-10-06T09:50:54.000Z' with php

This code :
$timestamp = 2016-10-06T09:50:54.000Z;
How do I separate or convert from the timestamp into a date and time?
example :
TimeStamp 2016-10-06T09:50:54.000Z
Date 2016-10-06
Jam(GMT +7) 04:55:45
Please help to solve this problem. Thanks
$d = new DateTime('2016-10-06T09:50:54.000Z');
echo $d->format('Y-m-d\TH:i:s.u'); // 2016-10-06T09:50:54.000000
echo $d->format('Y-m-d'); // 2016-10-06
// convert to GMT+7 timezone
$d->setTimezone(new DateTimeZone('GMT+7'));
echo $d->format('h:i:s'); // 04:50:54
<?php
$timestamp = "2016-10-06T09:50:54.000Z";
$datetime = new Datetime('2016-10-06T09:50:54.000Z');
echo "Date".$datetime->format('Y-m-d')."<br>";
echo "Jam".$datetime->format('H:i:s');
?>
Take a look at this short example:
<?php
$datetime = new Datetime('2016-10-06T09:50:54.000Z');
var_dump($datetime->format('Y-m-d H:i:s'));
The output obviously is: string(19) "2016-10-06 09:50:54"
Using different format strings you can convert your date time object into whatever representation you want to. 'Y-m-d' will give the date in international format for example.
Take a look at the great documentation: http://php.net/manual/en/class.datetime.php
Not much of a mystery:
<?php
$timestamp = '2016-10-06T09:50:54.000Z';
$dt = new DateTime($timestamp);
var_dump($dt);
$dt->setTimezone(new DateTimeZone('Asia/Jakarta'));
var_dump($dt);
object(DateTime)#1 (3) {
["date"]=>
string(26) "2016-10-06 09:50:54.000000"
["timezone_type"]=>
int(2)
["timezone"]=>
string(1) "Z"
}
object(DateTime)#1 (3) {
["date"]=>
string(26) "2016-10-06 16:50:54.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(12) "Asia/Jakarta"
}
Unlike strings, giving format to a proper date is trivial.
I don't know what time zone Jam is but I suggest you assign a city so you can account for DST (I've used Asia/Jakarta in my sample code, the complete list can be found at List of Supported Timezones). Just relying on a UTC offset like +7 may make your code unreliable during the summer.

Categories