1. ホーム
  2. c#

うるう年のバグを防ぐためのコーディングプラクティスを開発するには?[クローズド]

2023-09-06 23:58:26

質問

マイクロソフトは、日付の計算におけるソフトウェア エラー (うるう年以上) について によって Windows Azure に大規模な障害が発生したことを発表しました。 を引き起こしたことを発表しました。

を回避するための単純な判断ミスだったのでしょうか? DateTime.Now.AddYears(1) を閏年で使うというのは、本当に単純な判断ミスだったのでしょうか?

どのようなコーディングプラクティスがこれを防ぐことができたのでしょうか?

EDIT dcstrawさんが指摘されているように DateTime.Now.AddYears(1) をうるう年で実行すると、.NETでは実際に正しい日付が返されます。 つまり、これはフレームワークのバグではなく、明らかに日付計算のバグです。

どのように解決するのですか?

恥知らずのプラグ。

より良い日付と時刻のAPIを使う

組み込みの.NETの日付と時刻のライブラリは、適切に使用するのが恐ろしく難しいです。それらは は必要なことをすべて実行できますが 表現する は、型システムを通して自分自身を明確に表現することができます。 DateTime は混乱 , DateTimeOffset は、タイムゾーンの情報を実際に保存していないにもかかわらず、保存しているように思わせるかもしれませんし、また TimeZoneInfo は、考慮すべきすべてのことについて考えることを強制するものではありません。

また、ローカルタイムと特定のタイムゾーンの時間との間の明確な区別をすることもできません。また、グレゴリオ暦以外の暦を使いたい場合は Calendar クラスをずっと使い続けなければなりません。

これらのことから、私が作っている 野田時間 - の移植版である代替の日付と時刻のライブラリーを作っています。 ヨーダ時間 エンジン"engine" の移植版ですが、新しい(そしてより無駄のない)APIが上に乗っています。

意識しないと見逃しがちな、考えたいポイントもあります。

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

具体的な開発手法としては

  • 何を本当に表現しようとしているのかを考える。 Noda Timeの核となる利点は、開発者にデータを表現するために様々な異なるタイプの中から選択することを強いることだと期待しています。それを正しく理解することで、他のすべてがよりシンプルになるのです。
  • 思いつく限りのすべてをユニットテストしてください。もちろん、それはあなたのシステムが何をするのかによりますが 特に は、異なるタイムゾーン、夏時間の移行で何が起こるか、そしてもちろんうるう年を考慮してください。
  • を明示的に呼び出すのではなく、現在の時刻を伝えるためのサービスである時計のようなインターフェイスを注入することをお勧めします。 DateTime.Now または DateTime.UtcNow ユニットテストが容易になります。
  • 複数の操作を"now"で行っている場合、その日時を取得する 一度だけ を繰り返し要求するのではなく、一度だけ取得し、それを覚えておいてください。
  • すべてを UTC で行うことは、常に答えとなるわけではありません。 ローカル の日付/時刻とタイムゾーンを保存する必要があります。