2017-05-03 49 views
0

我正在PHP中使用時間戳和基於時間戳的計算值(計算對我的問題無關緊要)實施表。PHP日期時間添加在DST錯誤

在夏令時到冬令時(夏令時)的轉換中使用add方法時,我注意到了PHP的DateTime對象中一個非常奇怪的行爲。

在我的例子,我加入15分鐘的時間戳進行打印(使用本地格式,UNIX UTC時間戳和時間戳秒偏移):

<?php 

date_default_timezone_set('Europe/Vienna'); 

$offset = new DateInterval("PT15M"); 

foreach([new DateTime("2016-03-27 01:00:00"), 
     new DateTime("2016-10-30 01:00:00")] as $dt) { 
    $lastTs = NULL; 

    for($j = 0; $j < 12; $j++) { 
     echo $dt->format('d.M.Y H:i:s P (U)'); 

     if(!is_null($lastTs)) 
      echo ' (+' . ($dt->format('U') - $lastTs) . ')'; 

     $lastTs = $dt->format('U'); 

     echo "\n"; 

     $dt->add($offset); 
    } 

    echo "\n"; 
} 

這個小劇本給了我這樣一個表(注意30.Oct.2016 02:15上的巨大跳躍):

27.Mar.2016 01:00:00 +01:00 (1459036800) 
27.Mar.2016 01:15:00 +01:00 (1459037700) (+900) 
27.Mar.2016 01:30:00 +01:00 (1459038600) (+900) 
27.Mar.2016 01:45:00 +01:00 (1459039500) (+900) 
27.Mar.2016 03:00:00 +02:00 (1459040400) (+900) 
27.Mar.2016 03:15:00 +02:00 (1459041300) (+900) 
27.Mar.2016 03:30:00 +02:00 (1459042200) (+900) 
27.Mar.2016 03:45:00 +02:00 (1459043100) (+900) 
27.Mar.2016 04:00:00 +02:00 (1459044000) (+900) 
27.Mar.2016 04:15:00 +02:00 (1459044900) (+900) 
27.Mar.2016 04:30:00 +02:00 (1459045800) (+900) 
27.Mar.2016 04:45:00 +02:00 (1459046700) (+900) 

30.Oct.2016 01:00:00 +02:00 (1477782000) 
30.Oct.2016 01:15:00 +02:00 (1477782900) (+900) 
30.Oct.2016 01:30:00 +02:00 (1477783800) (+900) 
30.Oct.2016 01:45:00 +02:00 (1477784700) (+900) 
30.Oct.2016 02:00:00 +02:00 (1477785600) (+900) 
30.Oct.2016 02:15:00 +01:00 (1477790100) (+4500) 
30.Oct.2016 02:30:00 +01:00 (1477791000) (+900) 
30.Oct.2016 02:45:00 +01:00 (1477791900) (+900) 
30.Oct.2016 03:00:00 +01:00 (1477792800) (+900) 
30.Oct.2016 03:15:00 +01:00 (1477793700) (+900) 
30.Oct.2016 03:30:00 +01:00 (1477794600) (+900) 
30.Oct.2016 03:45:00 +01:00 (1477795500) (+900) 

27. 27.一切看起來都正確。但是回到冬天的時候,會有一個巨大的跳躍。我不認爲這是DST的工作原理。

相反,我真的很想看到這個輸出中(在記事本編輯):

30.Oct.2016 01:45:00 +02:00 (1477784700) (+900) 
30.Oct.2016 02:00:00 +02:00 (1477785600) (+900) 
30.Oct.2016 02:15:00 +02:00 (1477786500) (+900) 
30.Oct.2016 02:30:00 +02:00 (1477787400) (+900) 
30.Oct.2016 02:45:00 +02:00 (1477788300) (+900) 
30.Oct.2016 02:00:00 +01:00 (1477789200) (+900) 
30.Oct.2016 02:15:00 +01:00 (1477789200) (+900) 
30.Oct.2016 02:30:00 +01:00 (1477791000) (+900) 
30.Oct.2016 02:45:00 +01:00 (1477791900) (+900) 
30.Oct.2016 03:00:00 +01:00 (1477792800) (+900) 
30.Oct.2016 03:15:00 +01:00 (1477793700) (+900) 

現在02:00出現2次,但具有不同的偏移(和corret UNIX時間戳)。

需要對我的代碼進行哪些更改才能獲得如上所示的正確結果?

回答

0

有沒有辦法用DateTime對象與Europe/Vienna時區來實現它。

PHP不存儲時間戳,但本地時間+時區Check this answer for details。當你做$dt->format('U')它將本地時間轉換爲時間戳。 30.Oct.2016 02:15:00 (Europe/Vienna)可以解析爲2個時間戳:1477786500(Sun,2016年10月30日00:15:00 UTC)和1477790100(Sun,2016年10月30日01:15:00 UTC)。由於含糊不清,PHP挑選了後者,這會打破你的計算。

的解決方法是使用UTC時區的任何日期時間的操作,並將其轉換爲本地時區僅適用於輸出:

$utc = new DateTimeZone('utc'); 
$viena = new DateTimeZone('Europe/Vienna'); 

$offset = new DateInterval("PT15M"); 

foreach([new DateTime("2016-03-26 23:00:00", $utc), 
     new DateTime("2016-10-29 23:00:00", $utc)] as $dt) { 
    $lastTs = NULL; 

    for($j = 0; $j < 12; $j++) { 
     $local = clone $dt; 
     $local->setTimeZone($viena); 
     echo $local->format('d.M.Y H:i:s P'); // <== the only place where you need local timezone 
     echo $dt->format(' (U)'); 

     if(!is_null($lastTs)) 
      echo ' (+' . ($dt->format('U') - $lastTs) . ')'; 

     $lastTs = $dt->format('U'); 

     echo "\n"; 

     $dt->add($offset); 
    } 

    echo "\n"; 
} 
+0

我只注意到使用DATETIME的是,MySQL不相同。我是否應該使用UNIX時間戳存儲所有時間戳,因爲像DATETIME這樣的抽象根本無法正確計算? –

+0

時間戳或帶UTC時區的DateTime執行作業。 –

+0

你有什麼線索爲什麼MySQL NOW()默認不輸出UTC? MySQL-devs是否希望你將本地時間存儲在DATETIME中? –