PHP daylight saving time detection

2019-01-06 15:15发布

问题:

I need to send an email to users based wherever in the world at 9:00 am local time. The server is in the UK. What I can do is set up a time difference between each user and the server's time, which would then perfectly work if DST didn't exist.

Here's an example to illustrate it:

  • John works in New York, -5 hours from the server (UK) time
  • Richard works in London, UK, so 0 hour difference with the server.

When the server goes from GMT to GMT +1 (BST) at 2:00am on a certain Sunday, this means that John now has a -6H time difference now.

This scenario I can still handle by updating all the users outside the server's local time, but once I've moved forward/backward the time of all the other users, I still need a way to detect when (time and date) the users living outside the UK will (or will not) change their local time to a probable DST one.

I need a PHP method to know/detect when other parts of the world will enter/exit DST.

回答1:

Do you need to know all the details of DST transition yourself? or do you just need to know when is 9:00 am in a given timezone?

If it's the latter, PHP can use your operating system's timezone database to do that for you. The strtotime() function is remarkably good at "figuring out" what you mean:

echo strtotime("today 9:00 am America/New_York");  // prints "1306501200"
echo strtotime("today 9:00 am Europe/London");     // prints "1306483200"

Just make sure you're using one of the PHP supported timezones.



回答2:

As Jimmy points out you can use timezone transitions, but this is not available on PHP <5.3. as dateTimeZone() is PHP>=5.2.2 but getTransitions() with arguments is not! In that case here is a function that can give you timezone data, including whether in DST or not.

function timezonez($timezone = 'Europe/London'){
    $tz = new DateTimeZone($timezone);
    $transitions = $tz->getTransitions();
    if (is_array($transitions)){
        foreach ($transitions as $k => $t){
            // look for current year
            if (substr($t['time'],0,4) == date('Y')){
                $trans = $t;
                break;
            }
        }
    }
    return (isset($trans)) ? $trans : false;
}

Having said that, there is a simpler method using date() if you just need to know whether a timezone is in DST. For example if you want to know if UK is in DST you can do this:

date_default_timezone_set('Europe/London');
$bool = date('I'); // this will be 1 in DST or else 0

... or supply a timestamp as a second arg to date() if you want to specify a datetime other than your current server time.



回答3:

Changing my answer a bit: DateTimeZone::getTransitions looks like it will do what you need, provided you have PHP >= 5.2.

From a comment in the documentation:

<?php 
$theTime = time(); // specific date/time we're checking, in epoch seconds. 

$tz = new DateTimeZone('America/Los_Angeles'); 
$transition = $tz->getTransitions($theTime, $theTime); 

// only one array should be returned into $transition. Now get the data: 
$offset = $transition[0]['offset']; 
$abbr = $transition[0]['abbr']; 
?>

So here, all we need to do is pass in the timezone we want to check and we can know if that timezone is in DST/what the offset is. You'll then need to check the offset against GMT to see if you want to send your e-mail now, or not now.