Reputation: 20825
The problem is, that for example 2:00am or 2:59am are doubled in autumn in some timezones and don't exist in spring during the DST time-saving change.
If I run a PHP loop through every minute through a whole year, how can I catch the DST timesavings hour within the loop? (in the current Timezone, set by date_default_timezone_set)
How would I complete a PHP 5.2 compatible function like:
<?php
/** returns true if a time is skipped or doubled
* (for example "2013-03-10 02:30" doesen't exist in USA)
*
* @param string $season
* @param string $datestring in the form of "2013-03-10 02:30"
* @return boolean
**/
function checkDST($datestring,$season="any"){
$tz=date_default_timezone_get();
$season=strtolower(trim($season));
if($season=="spring"){
if(/* an hour skipped */) return true;
}else if($season=="autumn"){
if(/* double hour */) return true;
} else if($season=="any") {
if(/* any of both */) return true;
}
return false
}
so I could use
date_default_timezone_set("America/New_York");
$is_skipped=checkDST("2013-03-10 02:30","spring");
and
$exists_two_times=checkDST(2003-11-03, 02:00,"autumn"); // or 2:59 for example
(Timezones see: http://www.timeanddate.com/worldclock/clockchange.html?n=224&year=2013 )
EDIT:
I found out how to detect the spring DST:
function checkDST($datestring,$season="any"){
var_dump('checking '.$datestring);
$season=strtolower(trim($season));
$datestring=substr($datestring,0,16);
if($season!="autumn" and date("Y-m-d H:i",strtotime($datestring))!=$datestring) {
return true;
}
// check for double hours in autumn
...
Upvotes: 3
Views: 2434
Reputation: 20825
This works on all times in
date_default_timezone_set("America/New_York");
There is only still one bug, if I call it for europe, it sais the hour is one hour early:
date_default_timezone_set("Europe/Berlin");
var_dump(checkDST("2013-10-27 01:30","any"));
var_dump(checkDST("2013-10-27 02:30","any"));
(The savings hour in europe is from 2am till 3am)
This is the conclusion so far:
<?php
/** returns true if a time is skipped or doubled
* (for example "2013-03-10 02:30" doesen't exist in USA)
*
* @param string $season "spring", "autumn", "fall" or any other string for any of the time changes
* @param string $datestring in the form of "2013-03-10 02:30"
* @return boolean
**/
function checkDST($datestring, $season, $tz = null){
$debug=true;
if($debug) echo ('checking '.$season.' '.$datestring);
$season=strtolower(trim($season));
if($season=="fall") $season="autumn";
$datestring=substr($datestring,0,16);
$monthdaystring=substr($datestring,0,10);
if(!strtotime($datestring) or date("Y-m-d",strtotime($monthdaystring))!=$monthdaystring) {
//Error
if($debug) echo "<br>Error: not a correct datestring: $datestring";
return false;
}
if($season!="autumn" and date("Y-m-d H:i",strtotime($datestring))!=$datestring) {
// spring or any
if($debug) echo "<br>".(date("Y-m-d H:i",strtotime($datestring)).'!='.$datestring);
return true;
} else if($season=="spring") {
// spring ends here
return false;
}
// "autumn" or "any"
$timestamp = strtotime($datestring);
$timestamp_start = new DateTime();
$timestamp_start->setTimestamp($timestamp);
$timestamp_end = new DateTime();
$timestamp_end->setTimestamp($timestamp)->add(new DateInterval('PT3600S'));
if (!$tz) $tz = date_default_timezone_get();
$timezone = new DateTimeZone($tz);
$transitions = $timezone->getTransitions($timestamp_start->getTimestamp(), $timestamp_end->getTimestamp());
if (count($transitions) > 1) { // there's an imminent DST transition, spring or fall
// autumn
if($debug) echo "<br>NumTransitions: ".(count($transitions));
if($debug) var_dump($transitions);
return true;
}
return false;
}
Upvotes: 0
Reputation: 1636
If you're using PHP's date_default_timezone_set to parse what I assume to be Unix timestamps, the timestamps will be parsed relative to that timezone. To then determine the Daylight Savings Time offset, if one is relevant, use DateTimeZone::getTransitions.
A function that worked similar to the one in your example might look like this:
<?php
function checkDST($datestring, $season, $tz = "America/New_York", $minutes_from_now_to_check = 1){
$seconds_to_check = ($minutes_from_now_to_check * 60) + 30;
if (!$tz) $tz = date_default_timezone_get();
$timestamp = strtotime($datestring);
$timestamp_start = new DateTime();
$timestamp_start->setTimestamp($timestamp);
$timestamp_end = new DateTime();
$timestamp_end->setTimestamp($timestamp)->add(new DateInterval('PT'.$seconds_to_check.'S'));
$timezone = new DateTimeZone($tz);
$transitions = $timezone->getTransitions($timestamp_start->getTimestamp(), $timestamp_end->getTimestamp());
if (count($transitions) > 1) { // there's an imminent DST transition, spring or fall
if (strtolower($season) == "spring" && $transitions[1]["isdst"] === true){
return true;
}
if (strtolower($season)=="autumn" && $transitions[1]["isdst"] === false){
return true;
}
if (strtolower($season)=="any"){
return true;
}
}
return false;
}
$is_skipped = checkDST("2013-03-10 01:59","spring");
var_dump($is_skipped); // will display bool(true)
$is_skipped = checkDST("2013-03-10 12:30","spring");
var_dump($is_skipped); // will display bool(false)
$exists_two_times=checkDST("2013-11-03 01:59","autumn");
var_dump($exists_two_times); // bool(true)
$exists_two_times=checkDST("2013-11-03 03:00","autumn");
var_dump($exists_two_times); // bool(false)
Upvotes: 2