システム全体のタイムゾーンデータベースを使用して、そのデータベースのカスタム更新を維持できます。
IANAの公式TZデータベースリポジトリ
これは、必要に応じて変更し、時間関数で使用できるバイナリファイルに再コンパイルできるソースファイルとして利用できますglibc
。その結果、これらの時間関数を使用するすべてのプログラムで使用できます。ディストリビューションがそのような更新を実行する場合、そのデータベースへの自動更新を無効にする方法を見つける必要があるかもしれません。そうしないと、カスタム変更が失われます。
PHPが実際にシステム全体のTZデータベースに準拠しているかどうかはわかりません。PECLtimezonedb
パッケージは、それがIANAデータベースの別個の再コンパイルされたバージョンであることを示しているようであるため、システム全体のデータベースの変更を監視しない可能性があります。
glibc
PHPがシステム全体のデータベースの変更を無視する場合は、タイムゾーン対応の時間関数を使用し、タイムゾーンオフセットの戻りをサポートする外部プログラムを呼び出すことで、ゾーンオフセットを取得できます。
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開始/終了時間を参照する必要があります。