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.
Related
I am working with the graph in PHP, and building a calendar widget for a site that should pull only today's events, including all day events.
Everything works, however it also pulls all day events for yesterday and I cannot figure out what I am doing wrong.
$today = new DateTime( 'now', new DateTimeZone( 'America/New_York' ) );
$tomorrow = new DateTime( 'tomorrow', new DateTimeZone( 'America/New_York' ) );
$start_date = $today->format('Y-m-d');
$end_date = $tomorrow->format('Y-m-d');
$events = ms_get_data_as_json( 'calendarview?startdatetime=' . $start_date . '&enddatetime=' . $end_date . '&$orderby=start/DateTime' );
the formatted request string outputs as calendarview?startdatetime=2018-05-18&enddatetime=2018-05-19&$orderby=start/DateTime which would appear to work correctly, however sending this request, the first object returned is an all day event for the previous day. See sample output:
[0] => stdClass Object
(
[createdDateTime] => 2018-05-18T13:30:37.8672462Z
[lastModifiedDateTime] => 2018-05-18T13:34:25.2248155Z
[categories] => Array
(
)
[originalStartTimeZone] => UTC
[originalEndTimeZone] => UTC
[reminderMinutesBeforeStart] => 1080
[isReminderOn] =>
[hasAttachments] =>
[subject] => Test yesterday
[bodyPreview] =>
[importance] => normal
[sensitivity] => normal
[isAllDay] => 1
[isCancelled] =>
[isOrganizer] => 1
[responseRequested] => 1
[seriesMasterId] =>
[showAs] => free
[type] => singleInstance
[onlineMeetingUrl] =>
[recurrence] =>
[responseStatus] => stdClass Object
(
[response] => organizer
[time] => 0001-01-01T00:00:00Z
)
[body] => stdClass Object
(
[contentType] => html
[content] =>
)
[start] => stdClass Object
(
[dateTime] => 2018-05-17T00:00:00.0000000
[timeZone] => UTC
)
[end] => stdClass Object
(
[dateTime] => 2018-05-18T00:00:00.0000000
[timeZone] => UTC
)
)
The start property is clearly for the prior date.
I've tried to change my query to include timestamps startdatetime=2018-05-18T00:00:01Z&enddatetime=2018-05-18T23:59:59Z yet I still get the same results. I've tried to change my $today and $tomorrow variables to use UTC, as the returned result says OriginalStartTimeZone is UTC, but I still get the same results.
Any help is appreciated.
I think there's a bit of an inequality problem in the way the apply the start/end dates filters, and it ends up including events that end on the start time (or start on the end time).
At the moment, it seems the solution is to add 1 second to the filter's start time, and subtract 1 second from the filter's end time. You'll still get all-day events for the requested date, but not all-day events for the previous or next day.
Let us know if you find situations which don't work with this method!
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
)
)
I've got strange behaviour with datetime's in php.
For some reason this code produces wrong result:
$period = new DatePeriod(
new DateTime('2017-03-20'),
DateInterval::createFromDateString('1 day'),
new DateTime('2017-03-31')
);
foreach($period as $dt){
$a[] = $dt->format('Y-m-d');
}
So expected result is period from 20 to 31, but it's not. Here is actual result:
Array
(
[0] => 2017-03-20
[1] => 2017-03-21
[2] => 2017-03-22
[3] => 2017-03-23
[4] => 2017-03-24
[5] => 2017-03-25
[6] => 2017-03-26
[7] => 2017-03-27
[8] => 2017-03-28
[9] => 2017-03-29
[10] => 2017-03-30
)
So what i'm missing here, or that's a php bug?
Following this user statement on official PhP documentation about DatePeriod::
[...] an example to include the end date using the DateTime method 'modify'
This class seems to ignore the end date. You will need to modify the end date to include this gap (of +1 unit, in your case +1 day).
From the JSON snippet that i got from a .net API query, I can't seem to convert the date /Date(1393477200000)/ properly in PHP.
I tried to do echo date('m/n/Y','1393477200000'); but it is still outputting the wrong date which is 07/7/46127 instead of the correct date of 2/27/2014.
Array
(
[status] => ok
[results] => Array
(
[0] => Array
(
[PROJECT_ID] => 1
[COMPANY_ID] => 1
[PROJECT_NAME] => The "Getting Started" Project
[PROJECT_NUMBER] => 000001
[CAN_OPEN_PROJECT] => 1
[DATE_START_DATE] => /Date(1393477200000)/
[DATE_END_DATE] => /Date(1440648000000)/
[PROJECT_DESC] =>
[TASK_NUMBER] => 6
[DATE_CREATED] => /Date(1409142925980)/
[TOTAL_TASKS] => 1
[TOTAL_INCOMPLETE_TASKS] => 1
[TOTAL_COMPLETED_TASKS] => 0
Any ideas how to format [DATE_START_DATE] correctly in PHP? Thanks!
Divide your unix-timestamp by 1000, then use date(..).
$date = '1393477200000';
echo date("m/d/y", $date/1000);
Its that simple.
Result:
02/27/14
echo date('m/d/Y',(1393477200000/1000)); U have to truncate last 3 digit.
The time received is in milliseconds... You have to divide by a thousand to retrieve UNIX epoch time:
echo date('m/d/Y',(1393477200000/1000));
And here is the fiddle
I'm currently writing a script that would extract all the dates from a message and convert them to timestamps. PHP's strtotime (similar to Unix's date -c 'some date') would be perfect for this, as it recognizes all kinds of dates, such as:
5pm today
2010-11-15 16:30
Thursday 8:00
However, I'm having trouble finding those dates in the first place. For example, in the following string,
I'll be there for dinner tomorrow at 9:00pm
I need to isolate "tomorrow at 9:00pm", as that's the part that strtotime recognizes.
Is there a regular expression or something similar that would return me all dates that can be parsed by strtotime?
The only thing I can think of is date_parse. A regular expression that matches any format accepted by strtotime would be huge.
An example of date_parse:
$str = "I'll be there for dinner tomorrow at 9:00pm";
$parsed = date_parse($str);
print_r($parsed);
It would output something like this (I removed the unimportant parts from it to make it the result lighter):
Array
(
[year] =>
[month] =>
[day] =>
[hour] => 21 // 9:00pm
[minute] => 0 // 9:00pm
[second] => 0 // 9:00pm
[fraction] => 0
[warning_count] => 1
[is_localtime] => 1
[zone_type] => 2
[zone] => -540
[is_dst] =>
[tz_abbr] => I
[relative] => Array
(
[year] => 0
[month] => 0
[day] => 1 // tomorrow (would be -1 for yesterday, etc.)
[hour] => 0
[minute] => 0
[second] => 0
)
)
Whether this works for you depends primarily on what your input looks like. If you have more than one instance of a date in your input string, it will not work as expected.
This might not be totally efficient, but should work for any date string that consists of up to 5 words in length. I would write the function, but I think you'll get the idea with the comments below...
$words = explode(' ',$original_string);
// Use the array_chunk() function break up this array into 1-word,
// 2-word, 3-word, and 4-word long substrings of the original string
// Reform them back into strings and pass each one through strtodate()