2

タスクは何ですか?
プロジェクトの仕様により、特定のタイム ゾーン オフセットの DST ルールを計算する必要があります。ソフトウェア構成に依存できず、一部の DST ルールが変更された場合にソフトウェア構成を更新できないため、 標準的なツールを介してルールを適用することはできません。date_default_timezone_set()

私は何を持っていますか?
DST 切り替え日が先週で、先週の切り替え日が翌月の場合、先週の数字を減らす必要があります。今のところ、私には醜い解決策 が1つしかありません。

 $week = 5;
 if (
     (1 + 7 * ($week - 1)) 
     + $start['day_of_week'] 
     - date('w', mktime(0, 0, 0, $start['month'], 1, date('Y', $start['timestamp']))) 
     > 
     date('t', $start['month'])) 
 {
     $week--;
 }

私は何を探していますか?
これに対する最も簡単な解決策のアイデア、またはリンクを探しています =)

4

1 に答える 1

1

システム全体のタイムゾーンデータベースを使用して、そのデータベースのカスタム更新を維持できます。

IANAの公式TZデータベースリポジトリ

これは、必要に応じて変更し、時間関数で使用できるバイナリファイルに再コンパイルできるソースファイルとして利用できますglibc。その結果、これらの時間関数を使用するすべてのプログラムで使用できます。ディストリビューションがそのような更新を実行する場合、そのデータベースへの自動更新を無効にする方法を見つける必要があるかもしれません。そうしないと、カスタム変更が失われます。

PHPが実際にシステム全体のTZデータベースに準拠しているかどうかはわかりません。PECLtimezonedbパッケージは、それがIANAデータベースの別個の再コンパイルされたバージョンであることを示しているようであるため、システム全体のデータベースの変更を監視しない可能性があります。

glibcPHPがシステム全体のデータベースの変更を無視する場合は、タイムゾーン対応の時間関数を使用し、タイムゾーンオフセットの戻りをサポートする外部プログラムを呼び出すことで、ゾーンオフセットを取得できます。

putenv('TZ=America/New_York');
$offset = exec('date +%z');

$offsetフォーマット±HHMMになりますので、追加の解析が必要になります。

現在の時刻とは異なる、特定のタイムスタンプの正しいオフセットを見つけることもできます。

$unix_timestamp = 1350757594;
$offset = exec('date +%z --date=@'.$unix_timestamp);

もちろん、escapeshellargタイムスタンプが信頼できないソースからのものである場合は、適切なフィルタリングが必要になります。

更新:これが単一のDSTルールセットの解決策です。外部リソースは使用されません

function calculate_offset($ts) {
    static $standard_offset = 2;    // = +2:00
    static $dst_offset      = 3;    // = +3:00
    static $dst_start       = 'last Sunday of March %d 1:00';
    static $dst_end         = 'last Sunday of October %d 1:00';

    date_default_timezone_set('UTC');

    $y = idate('Y', $ts);
    $start = strtotime(sprintf($dst_start, $y));
    $end = strtotime(sprintf($dst_end, $y));

    if ($start < $end) {
        // Northern hemisphere, DST starts earlier in the year than it ends
        $offset = ($ts >= $start && $ts < $end)? $dst_offset: $standard_offset;
    } else {
        // Southern hemisphere, DST ends earlier in the year than it starts
        $offset = ($ts >= $end && $ts < $start)? $standard_offset: $dst_offset;
    }
    $utc_time = strftime('%Y/%m/%d %H:%M:%S', $ts);
    $local_time = strftime('%Y/%m/%d %H:%M:%S', $ts + $offset * 60 * 60);
    printf("TS: %d; Offset: +%02d:00; UTC: %s; Local: %s\n", $ts, $offset, $utc_time, $local_time);
}

サンプルコードは、標準のヨーロッパのDSTルールと東ヨーロッパの時間オフセットを使用しています。DSTの開始ルールと終了ルールを次の形式で表現する方法を見つける必要がありますstrtotime相対形式。DSTの開始/終了ルールのA%dは、タイムスタンプが該当する年に置き換えられるため、月の平日ルールは特定の年の正しい日付を検出します。すべての計算はUTC時間で行われるため、ルールはUTCのDST開始/終了時間を参照する必要があります。

于 2012-11-01T08:17:07.640 に答える