Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DateTime with TimeZone to MongoDB\BSON\UTCDateTime

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?

like image 291
Čamo Avatar asked Dec 28 '18 17:12

Čamo


1 Answers

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.

like image 119
ModernDeveloperLLC Avatar answered Nov 02 '22 08:11

ModernDeveloperLLC