4

問題は、たとえば、一部のタイムゾーンでは午前 2:00 または午前 2:59 が秋に 2 倍になり、DST の時間節約の変更中に春には存在しないことです。

1 年を通して毎分 PHP ループを実行する場合、ループ内で DST の時間節約時間を把握するにはどうすればよいですか? ( date_default_timezone_setで設定された現在のタイムゾーン)

次のような PHP 5.2 互換関数を完成させるにはどうすればよいですか。

<?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
}

だから私は使うことができました

date_default_timezone_set("America/New_York");
$is_skipped=checkDST("2013-03-10 02:30","spring");  

$exists_two_times=checkDST(2003-11-03, 02:00,"autumn"); // or 2:59 for example

(タイムゾーンは次を参照してください: http://www.timeanddate.com/worldclock/clockchange.html?n=224&year=2013 )


編集:
春の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
    ...
4

2 に答える 2

3

PHP の date_default_timezone_set を使用して Unix タイムスタンプと思われるものを解析している場合、タイムスタンプはそのタイムゾーンを基準にして解析されます。次に、夏時間のオフセットを決定するには、該当する場合は DateTimeZone::getTransitions を使用します

あなたの例と同様に機能する関数は、次のようになります。

<?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)
于 2013-11-13T05:31:08.187 に答える
0

これは常に機能します

date_default_timezone_set("America/New_York");

まだバグが 1 つだけあります。ヨーロッパで言うと、時間が 1 時間早くなっています。

date_default_timezone_set("Europe/Berlin");
var_dump(checkDST("2013-10-27 01:30","any"));
var_dump(checkDST("2013-10-27 02:30","any"));

(ヨーロッパでの節約時間は午前 2 時から午前 3 時までです)

これまでの結論は次のとおりです。

<?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;
}
于 2013-11-13T20:55:33.907 に答える