うるう年のバグから保護するように設計されたコーディング手法をどのように開発できますか?[閉まっている]


80

Microsoftは、日付の計算におけるソフトウェアエラー(うるう年以上)先週、WindowsAzureの大規模な停止を引き起こしたと発表しました。

DateTime.Now.AddYears(1)うるう年を回避するための判断の単純な誤りでしたか?

どのようなコーディング慣行がこれを防ぐことができたでしょうか?

編集 うるう年でdcstrawが指摘したようDateTime.Now.AddYears(1)に、実際には.NETで正しい日付が返されます。したがって、これはフレームワークのバグではありませんが、明らかに日付計算のバグです。


7
「1つ」の答えはなく、これは議論の余地のある質問なので、プログラマーに移行する必要があると思います。また、常にコードをユニットテストします。常に。
ジョージストッカー2012年

2
DateTimeの問題は、厄介で複雑な問題です。UTCですべてを行うようなことを言うかもしれませんが、常に翻訳のポイントがあります...そしてそれが起こったとき、すべてのバグを回避するために考慮しなければならない順列の数は驚異的です。私たちのほとんどは、気にかけなければならないシステムで作業することは決してありません。
Josh

9
この質問は面白すぎて閉じることができないと思います:
Steven

11
締めくくりに4票?私はこれが悪い気性で、幸せなクローズをトリガーすることがSO進化の単なるフェーズであることを願っています。それはすべてあなたより少し聖すぎる。
イアンホルダー2012年

7
@IainMHは、特にそれを閉鎖したほとんどすべての人が数票以上の質問をしたことがないので、あなたに同意する必要があります。
ロイド

回答:


95

恥知らずなプラグ:

より良い日付と時刻のAPIを使用する

組み込みの.NET日付と時刻ライブラリを適切に使用するのは非常に困難です。彼らはない、あなたが必要なすべてをやらせる、しかし、あなたがすることができない表現型システムを通じて明確に自分自身を。DateTime混乱でDateTimeOffsetあなたはあなたがいないとき、実際にタイムゾーン情報を保存している、と考えることにあなたを小康状態かもしれTimeZoneInfoあなたが考慮されるべきであるすべてのものを考えるようにあなたを強制するものではありません。

これらはいずれも、「時刻だけ」または「日付だけ」を適切に表現するものではなく、「現地時間」と「特定のタイムゾーンの時間」を明確に区別するものでもありません。また、グレゴリオ暦以外のカレンダーを使用する場合は、Calendarクラス全体を受講する必要があります。

これらすべてが、私がNoda Timeを構築している理由です。これは、Joda Timeの「エンジン」のポート上に構築された代替の日付と時刻のライブラリですが、新しい(よりスリムな)APIが上部にあります。

あなたが考えたいと思うかもしれないいくつかのポイント、あなたがそれらに気づいていないなら見逃しがちです:

  • ローカルの日付/時刻を特定のタイムゾーンの日付/時刻にマッピングすることは、思ったほど簡単ではありません。夏時間の移行により、特定のローカル日付/時刻が1回、2回(あいまい)、または0回(スキップされる)発生する場合があります。
  • タイムゾーンは歴史的に異なります-TimeZoneInfo率直に言って、一般的に明らかにすることをいとわない以上のものです。(「標準時間」の概念が時間の経過とともに変化する、または恒久的な夏時間になるタイムゾーンはサポートされていません。)
  • zoneinfoデータベースを使用しても、タイムゾーンIDは必ずしも安定しているとは限りません。(CLDRはこれに対処します。私が最終的に野田時間でサポートしたいと思っていることです。)
  • 日付と時刻のテキスト表現は、順序だけでなく、日付区切り文字、時間区切り記号、および属格の月名などの奇妙なものに関しては悪夢です。
  • 1日の始まりは、必ずしも真夜中とは限りません。たとえば、ブラジルでは、春の夏時間の移行により、壁時計が午後11時59分59秒から午前1時に移動します。
  • 場合によっては(私が知っていることですが)、タイムゾーンによって1日がスキップされることがあります-2011年12月30日はサモアでは発生しませんでした!ほとんどの開発者はおそらくこれを無視できると思いますが...
  • グレゴリオ暦以外のカレンダーを使用する場合は、注意して、カレンダーの動作を本当に理解していることを確認してください。

特定の開発慣行に関する限り:

  • あなたが本当に表現しようとしていることについて考えてください。Noda Timeの主な利点は、開発者がデータを表すためにさまざまなタイプから選択することを余儀なくされることだと思います。それを正しく行うと、他のすべてがより簡単になります。
  • あなたが考えることができるすべてをユニットテストします。もちろん、それはシステムの動作に正確に依存しますが、特に異なるタイムゾーン、夏時間の移行全体で何が起こるか、そしてもちろんうるう年を考慮してください。
  • DateTime.Nowまたはを明示的に呼び出すのではなく、「時計のようなインターフェイス」(現在の時刻を通知するサービス)をDateTime.UtcNow挿入することをお勧めします。ユニットテストが簡単になります(実行可能です!)
  • 「now」で複数の操作を実行している場合は、「now」を繰り返し要求するのではなく、その日付/時刻を一度取得して覚えておいてください。そうしないと、呼び出し間で値が不幸な方法で変わる可能性があります。
  • 「UTCですべてを行う」も常に答えであるとは限りません。「自分のローカルタイムゾーンで「今から2週間後」が正確にいつ発生するか」を知りたい場合は、次に、ローカルの日付/時刻とタイムゾーンを保存する必要があります。

2
@flq:繰り返しになりますが、「うるう年の安全」とはどういう意味かを正確に定義する必要があります。私はそれがあったことを疑うフレームワークAzureの問題を引き起こしたバグ-私はそれが悪かった期待の使用フレームワークの。
Jon Skeet 2012年

10
うるう年(つまりトピック)をテーマにした広告の箇条書きは1つもありません。そしてツイッターでパフ。ジョン、あなたはもっと良い瞬間があったと思います。
ウィルディーン

8
@WillDean:質問はGeorgeStockerによって編集されたことにも注意してください。元のタイトルは「DateTimeバグに対する防御的なプログラミング」でした。その場合、私の投稿完全に関連していることに同意すると思います。(タイトルが変更されたことに気づいただけです。答え始めたときにDateTimeと表示されていました...)
Jon Skeet 2012年

2
ジョン、すみません、前のタイトルを見ていませんでした!たぶん、すべての回答を編集するためにタイトルを変更するのは誰かの責任であるはずです...
ウィルディーン

3
@WillDean:はい...タイトルの変更をロールバックするか、「DateTimeバグ(うるう年など)」で終了させたいと思っています
Jon Skeet 2012年

25

バグはおそらくあなたが投稿したような行によるものではなかったことは注目に値します:

DateTime.Now.AddYears(1)

無効な日付は作成されません。実行する場合:

(new DateTime(2012, 2, 29)).AddYears(1)

2013年2月28日を取得します。Azureのゲストエージェントが何で記述されているかはわかりませんが、別の呼び出しが失敗したに違いありません。.NETでこれを行うための悪い方法は次のとおりです。

new DateTime(today.Year + 1, today.Month, today.Day)

todayうるう日であれば例外をスローします。ただし、Azureの問題に関するMicrosoftのブログでは、2013年2月29日の無効な日付が作成されたと述べていDateTimeます。これは、.NETで実行できるかどうかはわかりません。

私はそれを言っているわけDateTimeDateTimeOffsetはなく、エラーが発生しやすいわけでもありません。ただ、彼らがこの特定の問題を引き起こしたとは思わないだけです。


私はそれがC ++で行われたと推測しています
PhilPursglove 2012年

2
@PhilPursglove:どうしてそう思うのですか?WindowsOSは主にCおよびC ++で記述されており、うるう日を適切に処理します。おそらく、転送証明書の作成プロセスにおける日付関連の失敗と関係がありました。
インシリコ2012年

文字列から日付を解析している可能性がありますか?
フィクサー2012年

そして、あなたが指摘したように、あなたはAddYears(1)について正しいです。内部で何が起こったのかわかりません。これは、ブログの投稿に深く入り込むことなく、質問に少し視点を与える試みにすぎませんでした。
フィクサー2012年

それはちょっと理にかなっています。正直なところ、これが事実かどうかはわかりませんが、信頼できます。MSを含む大企業からの厄介なコードを見たことがあります。しかし、繰り返しになりますが、私たちは実際には多くのことを行うことはできませんが、現時点では推測しています。
アルファ

2

うるう年のバグから保護するように設計されたコーディング手法をどのように開発できますか?どのようなコーディング慣行がこれを防ぐことができたでしょうか?

ジョンが述べたように、特定の日付の単体テストは、役立つ1つのコードプラクティスですが、私が「手動統合テスト」として定義したものに勝るものはありません。

開発/テストベッドサーバーの時計を変更し、時間が経過したときに何が起こるかを監視します。

これが「コーディングの慣行」であるかどうかの詳細にとらわれないでください-明らかに、カレンダーのすべての日付に対してこれを行うことはできません-関心のある日付を選択してください。2月29日は月末です。日付または夏時間の切り替え日。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.