PHP DateTime :: Diffはそれを間違っていますか?
質問
DateTime :: Diffは適切な間隔を計算し、夏時間(DST)と閏年を考慮に入れてください。どうやらそれはそうではありませんがそうではありません。ホラーのコード:
$d1 = new DateTime("2011-10-30 01:05:00", new DateTimeZone("Europe/Stockholm"));
$d2 = new DateTime("2011-10-30 03:05:00", new DateTimeZone("Europe/Stockholm"));
echo $d1->getOffset() / (60 * 60);
.
印刷「2」を印刷します!したがって、UTC Time= 1H - 2H= 23:05:00前日に留意してください。
echo $d2->getOffset() / (60 * 60);
.
「1」を印刷します。 DSTが起こった。 UTC TIME= 3H - 1H= 02:05:00
$di = $d1->diff($d2);
echo "Hours of DateInterval: " . $di->h;
.
印刷「2」を印刷します!間違って?
$hoursofdiff = ($d2->getTimeStamp() - $d1->getTimeStamp()) / 60 / 60;
echo "Calculated difference in hours: $hoursofdiff";
.
印刷「3」!正しい?
与えられた日付の時計が03:00:00になったとき、すべてのスウェーデスは1時間から02:00:00までのクロックを回復しました。つまり、UNIXのタイムスタンプを使用するときに、手動計算がエコーされたときに、マニュアル計算がエコーされているのと同じように、01:05までの合計量が3時間です。アナログ時計を使うと私たちが指を計算するようになります。さらに、PHP独自のオフセット(!)を使用している2つのUTCタイムスタンプ間の違いを計算するとき(!)。
それはPHPですか、それとも私の脳は正常に仕事をやめましたか?このサイトに存在するすべての神々の誰かからの懲戒は私をとても幸せにするでしょう!
Apache-ServerでPHP 5.4(VC9)を使用しています。残念ながら私はOSとしてWindows 7 x 64を使います。私はPHPの日付/時刻クラスのバグのすべての請求に対して私のセットアップをテストしました(Windowsに関連したカップルがあります)、私のシステムにどれも持っていないことを確認できます。上記のコードを除いて、他のエラーが見つかりませんでした。私はすべてのコードを有効にしており、本「PHP Architectのガイドを日付と時刻のプログラミング」を提供しなければならなかった。それゆえ、私はそれが私の脳魔女がデフォルトである必要があると結論付けなければなりませんが、私はそれが最初に撮影したと思いました。
解決
正しい、PHPは現在DST遷移を処理していません...
バグレポート#51051 (まだ開いている)と
Daniel Convissorは while aを復帰しようとしていますが、変更 - これが対処されていることを示唆していないことをお勧めしません。私はこれが5.4で修正されることを願っていましたが、私はそれがあった証拠は見られません。
実行中の場合は、時間列に「DST」または「ST」を追加する必要があるように見えます。
ベストプラクティスは、この問題を回避するUTC ですべての日付計算を行うことです。
このDST Best Practices Post は非常に有益です。< / P>
他のヒント
PHP DateTimeクラスの関連バグのこのリストをお楽しみください。そのほとんどは2年以上前に開いています。
- https://bugs.php.net/bug.php?id=40743 < / a>
- https://bugs.php.net/bug.php?id=49914 < / a>
- https://bugs.php.net/bug.php?id=51051 < / a>
- https://bugs.php.net/bug.php?id=51557 < / a>
- https://bugs.php.net/bug.php?id=52480 < / a>
- https://bugs.php.net/bug.php?id=54340 < / a>
- https://bugs.php.net/bug.php?id=54655 < / a>
- https://bugs.php.net/bug.php?id=55253 < / a>
- https://bugs.php.net/bug.php?id=60873 < / a>
- https://bugs.php.net/bug.php?id=60960 < / a>
- https://bugs.php.net/bug.php?id=61022 < / a>
- https://bugs.php.net/bug.php?id=61311 < / a>
- https://bugs.php.net/bug.php?id=61530 < / a>
- https://bugs.php.net/bug.php?id=61955 < / a>
大丈夫ラッパークラスが作業しました。それは通過したリアルタイムを計算します。最初にそれはUTCからのオフセットを比較し、この時間差を引数として渡されたDateTimeオブジェクトに追加または減算します。その後、Parent :: diffを呼び出す以上のものは何もしません。よくわかりました私は、PHPのもう一つのバグがある可能性があるものをハックするために1つのライナーを紹介する必要がありました(下記のソースコードを参照)。 DateTimEdiff:diffメソッドはリアルタイムを渡します。それが何を意味するのかを理解するために、私はさまざまなさまざまな日付と時代を使ってこのクラスをテストし、私がこのコメントの下部にも含まれているあなたの作業負荷を助けてください。私が書いたかなり単純なHTMLページ。このリンクは日付と時間の組み合わせのためのいくつかのアイデアを得るための良い出発点かもしれません:
https://wiki.php.net/rfc/datetime_and_daylight_saving_time
<?php
class DateTimeDiff extends DateTime
{
public function diff($datetime, $absolute = false)
{
// Future releases could fix this bug and if so, this method would become counterproductive.
if (version_compare(PHP_VERSION, '5.4.0') > 0)
trigger_error("You are using a PHP version that might have adressed the problems of DateTime::diff", E_USER_WARNING);
// Have the clock changed?
$offset_start = $this->getOffset();
$offset_end = $datetime->getOffset();
if ($offset_start != $offset_end)
{
// Remember the difference.
$clock_moved = $offset_end - $offset_start;
// We wouldn't wanna mess things up for our caller; thus work on a clone.
$copy = clone $datetime;
if ($clock_moved > 0)
{
$timestamp_beforesub = $copy->getTimestamp();
// Subtract timedifference from end-datetime should make parent::diff produce accurate results.
$copy->sub( DateInterval::createFromDateString("$clock_moved seconds") );
// No change occured; sometimes sub() fails. This is a workable hack.
if ($timestamp_beforesub == $copy->getTimestamp())
$copy->setTimezone(new DateTimeZone("UTC"));
}
else // ..else < 0 and its a negative.
{
$clock_moved *= -1;
// Adding that timedifference to end-datetime should make parent::diff produce accurate results.
$copy->add( DateInterval::createFromDateString("$clock_moved seconds") );
}
return parent::diff($copy, $absolute);
} // <-- END "if ($offset_start != $offset_end)"
return parent::diff($datetime, $absolute);
}
}
?>
.
とテストのページ(DateTime :: DiffとDatetImeDiff :: diffの両方を使用して結果を表示します):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>DateTimeDiff-class</title>
<?php
if (! (empty($_GET['identifier']) && empty($_GET['start']) && empty($_GET['end'])))
{
$dt1_new = new DateTimeDiff("{$_GET['start']} {$_GET['identifier']}");
$dt1_old = new DateTime("{$_GET['start']} {$_GET['identifier']}");
$dt2 = new DateTime("{$_GET['end']} {$_GET['identifier']}");
$di_new = $dt1_new->diff($dt2);
$di_old = $dt1_old->diff($dt2);
// Extract UNIX timestamp and transitional data
$timezone_start = $dt1_new->getTimezone();
$timezone_end = $dt2->getTimezone();
$timestamp_start = $dt1_new->getTimeStamp();
$timestamp_end = $dt2->getTimeStamp();
$transitions_start = $timezone_start->getTransitions($timestamp_start, $timestamp_start);
$transitions_end = $timezone_end->getTransitions($timestamp_end, $timestamp_end);
echo <<<BUILDCONTAINER
<script type='text/javascript'>
function Container() { }
var c_new = new Container;
var c_old = new Container;
var t_start = new Container;
var t_end = new Container;
</script>
BUILDCONTAINER;
echo <<<SETTRANSITIONS
<script type='text/javascript'>
t_start.ts = '{$transitions_start[0]['ts']}';
t_start.time = '{$transitions_start[0]['time']}';
t_start.offset = '{$transitions_start[0]['offset']}';
t_end.ts = '{$transitions_end[0]['ts']}';
t_end.time = '{$transitions_end[0]['time']}';
t_end.offset = '{$transitions_end[0]['offset']}';
</script>
SETTRANSITIONS;
foreach ($di_new as $property => $value)
echo "<script type='text/javascript'>c_new.$property = $value</script>";
foreach ($di_old as $property => $value)
echo "<script type='text/javascript'>c_old.$property = $value</script>";
}
?>
<script type='text/javascript'>
window.onload = function()
{
if (c_new != null) // <-- em assume everything else is valid too.
{
// Update page with the results
for (var prop in c_new)
addtext(prop + ": " + c_new[prop] + " (" + c_old[prop] + ")");
addtext("Read like so..");
addtext("PROPERTY of DateInterval: VALUE using DateTimeDiff::diff ( VALUE using DateTime::diff )");
// Restore values sent/recieved
<?php
foreach ($_GET as $key => $value)
echo "document.getElementById('$key').value = '$value';";
?>
// Display transitiondata (For DateTime start)
var p_start = document.getElementById('p_start');
var appendstring = "TS: " + t_start.ts + ", Time: " + t_start.time + ", Offset: " + t_start.offset;
p_start.appendChild(document.createTextNode(appendstring));
// Display transitiondata (For DateTime end)
var p_end = document.getElementById('p_end');
appendstring = "TS: " + t_end.ts + ", Time: " + t_end.time + ", Offset: " + t_end.offset;
p_end.appendChild(document.createTextNode(appendstring));
}
}
function addtext()
{
var p = document.createElement("p");
p.appendChild(document.createTextNode(arguments[0]));
document.forms[0].appendChild(p);
}
</script>
</head>
<body>
<form action="test2.php" method="get">
<p>Identifier: <input type="text" name="identifier" id="identifier" value="Europe/Stockholm" /></p>
<p id="p_start">Start: <input type="text" name="start" id="start" /></p>
<p id="p_end">End: <input type="text" name="end" id="end" /></p>
<p><input type="submit" /></p>
</form>
</body>
</html>
.