I'm having trouble understanding how my code adapts to DST, as it's incorrect with the recent update. I'm storing a date time in the database based on UTC and then converting it back to the local timezone for display. If PHP is taking DST into account, something else is wrong because all of my stored dates are 1 hour off.
$stored_date = '2016-11-16 12:04:01'; // in UTC
$dateTime = new DateTime($stored_date, new DateTimeZone('UTC'));
$dateTimeZone = new DateTimeZone('America/New_York');
$dateTime->setTimezone($dateTimeZone);
print_r($dateTime);
Last week, before DST ended, this would have printed out 2016-11-16 08:04:01. This week, now that DST has ended, it prints out 2016-11-16 07:04:01. Why the hour difference if PHP is properly handing the DST shift?
It shouldn't matter the server settings (I don't think) because I'm explicitly doing the conversion within PHP, right?
I'm ready to start doing a check with PHP to see if DST is in effect and offsetting the conversion by 1 hour because I can't figure out why that hour isn't being automatically compensated for within the DateTime class.
New York city switches between these time zones:
Winter: EST (Eastern Standard Time) = UTC -5
Summer: EDT (Eastern Daylight Time) = UTC -4
According to timeanddate.com the switch will happen on 6th of November. Thus the result is correct: 12 - 5 = 7
In other words, PHP is perfectly aware of DST, as we can see in the following code:
$dateTime = new DateTime('2016-11-05 12:04:01', new DateTimeZone('UTC'));
$dateTime->setTimezone(new DateTimeZone('America/New_York'));
echo $dateTime->format('r') . PHP_EOL;
$dateTime = new DateTime('2016-11-06 12:04:01', new DateTimeZone('UTC'));
$dateTime->setTimezone(new DateTimeZone('America/New_York'));
echo $dateTime->format('r') . PHP_EOL;
Sat, 05 Nov 2016 08:04:01 -0400
Sun, 06 Nov 2016 07:04:01 -0500
You can inspect the exact information available in your system's time database:
$timeZone = new DateTimeZone('America/New_York');
print_r($timeZone->getTransitions(mktime(0, 0, 0, 1, 1, 2016), mktime(0, 0, 0, 12, 31, 2016)));
Array
(
[0] => Array
(
[ts] => 1451602800
[time] => 2015-12-31T23:00:00+0000
[offset] => -18000
[isdst] =>
[abbr] => EST
)
[1] => Array
(
[ts] => 1457852400
[time] => 2016-03-13T07:00:00+0000
[offset] => -14400
[isdst] => 1
[abbr] => EDT
)
[2] => Array
(
[ts] => 1478412000
[time] => 2016-11-06T06:00:00+0000
[offset] => -18000
[isdst] =>
[abbr] => EST
)
)
Related
I've got a date like : $date = DateTime::createFromFormat('D d/m', 'Mon 05/02'); but instead of 05 february the datetime returned is DateTime Object ( [date] => 2021-02-08 10:02:10.000000 [timezone_type] => 3 [timezone] => Europe/Brussels )
Answer
Corrected with the Y input and got the right result, php was using 2021 when i was constructing 2022 year
If the (wrong) day of the week is to be ignored, then an * only needs to be set in the format instead of the "D".
$date = DateTime::createFromFormat('* d/m', 'Mon 05/02');
"Mon" is ignored and the expression "05/02" is used to determine the date.
DateTime::__set_state(array(
'date' => "2021-02-05 18:28:31.000000",
'timezone_type' => 3,
'timezone' => "Europe/Berlin",
))
Because in 2021, February 5 is Friday, and February 8 is Monday.
SCENARIO
So I've custom object where I've three fields called start_date, end_date and booking_expire_time(for an event).
My dates are coming from Magento in form of String ofc, I already have logged so they are coming like
Thu Aug 30 09:46:16 2018 [8779][ffba8854-e7c0-11e6-85b6-06ec5399a877][FATAL] $start_date - 08/30/2018 11:59 AM
Thu Aug 30 09:46:16 2018 [8779][ffba8854-e7c0-11e6-85b6-06ec5399a877][FATAL] $event_endt_time - 08/31/2018 11:59 AM
Thu Aug 30 09:46:16 2018 [8779][ffba8854-e7c0-11e6-85b6-06ec5399a877][FATAL] $booking_expire_time - 08/30/2018 12:59 PM
Which is correct and same which I've chosen in Magento
And I'm storing it like following in that bean.
$st = date_create_from_format("m/d/Y H:i A",$start_date);
$eventBean->start_date = date_format($st, 'Y-m-d H:i:s');
$en = date_create_from_format("m/d/Y H:i A",$event_end_time);
$eventBean->event_end_time = date_format($en, 'Y-m-d H:i:s');
$ex = date_create_from_format("m/d/Y H:i A",$booking_expire_time);
$eventBean->booking_expire_time = date_format($ex, 'Y-m-d H:i:s');
ISSUE
There is no problem for saving except when I go to the UI and check date and time, the date and time are different.
I tried changing user timezone and storing it again but it is still same, I tried setting the timezone to UTC in User settings but still, the same thing is happening.
I've logged the date time which getting retrieved in code and it prints following for start date and end date
DateTime Object
(
[date] => 2018-08-30 11:59:00.000000
[timezone_type] => 3
[timezone] => UTC
)
DateTime Object
(
[date] => 2018-08-31 11:59:00.000000
[timezone_type] => 3
[timezone] => UTC
)
EDIT
Timezone setting
PHPInfo from Diagnostic Tool
I'm fetching emails using PHP Imap and this is an example of an object:
Array
(
[0] => stdClass Object
(
[subject] => Email Subject
[from] => Sender <sender#domain.com>
[to] => me#domain.com
[date] => Sat, 19 Aug 2017 20:09:33 +1000
[message_id] => <80d657c74967c8dc56138ca9552f0a2e#anyweb.apca.local>
[size] => 1881518
[uid] => 703
[msgno] => 527
[recent] => 0
[flagged] => 0
[answered] => 0
[deleted] => 0
[seen] => 0
[draft] => 0
[udate] => 1503137430
)
)
Although I do have a udate but I wanted to double check if matches my timezone, so I did:
date_default_timezone_set('Australia/Melbourne');
$str = 'Sat, 19 Aug 2017 20:09:33 +1000';
echo strtotime($str); // 1503137373 ??
Even tried:
$date = new DateTime($str, new DateTimeZone('Australia/Melbourne'));
$timestamp = $date->format('U');
echo $timestamp; // 1503137373 ??
So in both cases I get a timestamp that doesn't match the one thats fetched from the mail server, what am I missing here?
udate - labeled by a mailserver
Date, date - labeled by a client
The difference between 'date' and 'udate' seems to be rather more than
just the way they're formatted.
'date' is the date that was written in the headers by the sender's
mail client, and probably bears little to do with reality. It's
dependent on your sender knowing what the correct time is; it could be
out by a few minutes, days, months or even years.
'udate' is the real date that the e-mail hit your IMAP server.
Use 'udate' if you want to do neat stuff like work out how much e-mail
you get sent on a daily basis - or, as I do, how much spam I get.
http://titanic.fauser.edu/php/function.imap-headerinfo.php.htm
From here:
date - The message date as found in its headers
Date - Same as date
udate - mail message date in Unix time
you can do something like this
date_default_timezone_set('Australia/Melbourne');
$script_tz = date_default_timezone_get();
if (strcmp($script_tz, ini_get('date.timezone'))){
echo 'Script timezone differs from ini-set timezone.';
} else {
echo 'Script timezone and ini-set timezone match.';
}
When user enters Date and time using 'input type=date name="date"' && 'input type=time name="time"' tags according to his/her timezone,
for eg :- If a user from India, (Asia/Kolkata) timezone entered a date : 1/22/14 and time : 5:30pm , I need to Convert it into UTC time stamp for storing it to DB, To Achive that
I used below code:-
$year=substr($date,0,4);
$month=substr($date,5,2);
$day=substr($date,8);
$hour=substr($time,0,2);
$minute=substr($time,3);
$clientzone=mysql_result(mysql_query("select timezone from c_users_extra where c_id='{$_SESSION['clientid']}'"),0,0); //Fetches the timezone of user
date_default_timezone_set($clientzone);//Setting default timezone to client timezone
$datetime = new DateTime("$year-$month-$day $hour:$minute:00");
$la_time = new DateTimeZone('UTC');
$datetime->setTimezone($la_time);
$values=$datetime->format('Y-m-d H:i:s');
$year=substr($values,0,4);
$month=substr($values,5,2);
$hour=substr($values,11,2);
$minutes=substr($values,14,2);
$seconds=substr($values,17,2);
$timestamp=mktime($hour,$minutes,$seconds,$month,$day,$year);//creating new timestamp from coverted
print_r(getdate($timestamp));//Result : Array ( [seconds] => 0 [minutes] => 30 [hours] => 6 [mday] => 22 [wday] => 3 [mon] => 1 [year] => 2014 [yday] => 21 [weekday] => Wednesday [month] => January [0] => 1390372200 )
//Expected Result : Array ( [seconds] => 0 [minutes] => 0 [hours] => 12 [mday] => 22 [wday] => 3 [mon] => 1 [year] => 2014 [yday] => 21 [weekday] => Wednesday [month] => January [0] => 1390372200 )
Why I get this wrong time stamp ?
Here is an object oriented example:
<?php
$date = '2014-01-22 18:15:00'; // assumed date is formatted correctly
$clientzone = 'America/New_York'; // assumed timezone is a valid one from your SQL
$dateObj = new DateTime($date, new DateTimeZone($clientzone));
echo "Original: " . $dateObj->format('Y-m-d H:i:sP') . "\n";
$dateObj->setTimezone(new DateTimeZone('UTC')); // convert to UTC
echo "Converted: " . $dateObj->format('Y-m-d H:i:sP') . "\n";
echo "Epoch: ".$dateObj->format('U');
?>
You can format that just like the date function.
The $date and $clientzone are assumed to be valid.
Can't you do something simpler like:
$user_time = strtotime($date);
$dateTimeZone = new DateTimeZone($timezone);
// get the offset from server time (UTC)
$tzOffset = $dateTimeZone->getOffset(new DateTime());
$result_time = $user_time - $tzOffset;
Try following function to convert Local date time to UTC date time
function LocaltoUTC($date_to_convert)
{
$local_timestamp = strtotime($date_t);
$UTC_timestamp += ((-(5.5)) * 3600); // 5.5 is UTC timezone or local timezone
$gmt_datetime = gmdate('y-m-d H:i:s', $UTC_timestamp);
return $gmt_datetime;
}
Here is a similar question. Take a look at Adjusting time zone in PHP with DateTime / DateTimeZone
There is a solution and a more comfortable way to do your task.
I have some code that handles dates and times. I think it's OK, but want to test that it works when the clocks go forwards for DST.
I can change the timezone using date_default_timezone_set('Europe/London');, and wondered if there is an easy to simulate being in DST without having to wait till the clocks change!
You don't provide details on what you want to test but I assume you have functions to do time-related stuff, e.g.:
function setExpiryTime(DateTime $start, $minutes){
}
The obvious test is to provide input parameters that will make your code cross DST boundaries. You can either find such information in your favourite search engine or run a simple PHP snippet:
<?php
$timezone = new DateTimeZone('Europe/London');
print_r( $timezone->getTransitions(mktime(0, 0, 0, 1, 1, date('Y')), mktime(0, 0, 0, 12, 31, date('Y'))) );
Array
(
[0] => Array
(
[ts] => 1388530800
[time] => 2013-12-31T23:00:00+0000
[offset] => 0
[isdst] =>
[abbr] => GMT
)
[1] => Array
(
[ts] => 1396141200
[time] => 2014-03-30T01:00:00+0000
[offset] => 3600
[isdst] => 1
[abbr] => BST
)
[2] => Array
(
[ts] => 1414285200
[time] => 2014-10-26T01:00:00+0000
[offset] => 0
[isdst] =>
[abbr] => GMT
)
)
Thus you can test:
setExpiryTime(new DateTime('2014-03-30T00:55:00+0000'), 10);
setExpiryTime(new DateTime('2014-10-26T00:55:00+0000'), 10);
you can certainly find out, whether user is in Daylight saving zone or daylight saving is currently in effect.
echo date('I', time());
This returns 0/1; where,
0 = Daylight saving is not in effect.
1 = Daylight saving is in effect.
more details : http://php.net/manual/en/function.date.php
Based on this result you can make conditional code to simulate your output.