BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース .NET 6:日付と時刻の構造

.NET 6:日付と時刻の構造

原文(投稿日:2021/04/13)へのリンク

.NETの基本クラスライブラリの長年の問題は、日付と時刻の値を別々に表すことができないことである。.NET 6の一部として、新しいDateOnlyクラスとTimeOnlyクラスは、この過失を修正しようとするものである。

90年代以降、Windowsプログラマは、日付と時刻の値に関する最適とは言えない言い分に対処してきた。Visual Basicには、日付、時刻、日付と時刻、期間の値に使われるDateクラスのみがあった。これにより、日付コンポーネントしか保持するつもりがなかった値に対して、時間コンポーネントも取得しようとする場合によく問題が発生した。その逆も同じである。

.NET 1(VB 7)では、Date構造の名前がDateTimeに変更された。より適切な名前であるが、日付のみの値と日付+時刻の値の両方を表す必要があるという同じ問題があった。これは、タイムゾーン変換を実行するときに特に問題であった。DateTime構造に格納されている日付のみの値は、午前1時あるいは午後11時の時間コンポーネントを簡単に取得できる。後者の場合、1時間のオフセットにより、日付コンポーネントが前日に変更される。

また、.NET 1には、TimeSpan構造の導入があった。これは期間を保存するように設計された。しかし、多くの場合、その場しのぎの時間のみの構造として活用されていた。繰り返すが、この手法には問題があった。たとえば、午後10時に3時間を追加すると、予想される午前1時ではなく「1日と2時間」になる。多くの場合、これは、値がデータベースの時間のみの列に挿入されるまで気付かれず、その結果、オーバーフローエラーが発生する。

.NET 2では、DateTimeOffset構造が追加された。UTCからのオフセットを保持するフィールドを含めることで、タイムゾーンのシナリオに対応するためである。しかし、他の問題は未解決のままであった。

DateOnlyとTimeOnly

.NET 6まで進むと、DateOnlyTimeOnlyの提案があった。名前が示すように、これらの構造は、日付のみを保持するか、時刻のみを保持するように設計されている。単一責任の原則を正しく適用する数少ない例では、すでに説明した構造のような、複数の役割を果たすように求められるものはない。

前述のように、DateTime構造の元の名前は単にDateであった。これはVBでも継続され、Dateキーワードは引き続きDateTimeを参照する。そのため、混乱を避けるために、DateOnlyという名前が選択された。

DateOnlyという名前が選択されたもう1つの理由は、DateTime.DateがすでにDateTime値を返していることである。これは変更できないが、新たなプログラマはDateを返すことを期待するだろう。DateOnly型の呼び出しについて、新規の一致するプロパティをDateTime.DateOnlyで呼ぶことができる。

同様に、TimeOfDayに問題がある。多くのプロパティとメソッドがDateTime値あるいはTimeSpan値の参照に使用するためである。

シリアル化

DateOnlyTimeOnlyはSerializable属性を実装していない。.NET Core以降では、この属性に依存するシリアル化ライブラリと同じように、この属性は非推奨となる。

IXmlSerializable属性とそれと同等のJSONに対するリクエストがあった。ただし、DateOnlyTimeOnlyは、そのような属性が使用できないNETの最も低レベルのライブラリの1つに配置される。したがって、シリアライザーは、これらの新しいタイプに対して独自のカスタム処理を含める必要がある。そして、考慮すべきデータベースドライバーのようなものに組み込まれた完全にカスタムのシリアライザーがある。

このため、.NET 6がリリースされた後、シリアライザーが追いつくまで、一部のシナリオでDateOnlyTimeOnlyを使えない期間が発生する可能性がある。

DateTimeOnly

タイムゾーンの問題を解決するために、.NET 2ではDateTime.Kindプロパティが導入された。これは、開発者が日付+時刻の値に対して、その値がローカル、UTC、タイムゾーン未指定のいずれかを表すフラグでアノテーションを付ける選択肢を提供することを意味する。実際に起こったことは、開発者がこの情報を指定することを余儀なくされたか、予期しないバグに直面したことである。

さらに悪いことに、Kindプロパティは一貫して尊重されることはなかった。たとえば、多くのシリアライザーはそれを認識し、値をエクスポートするときにオフセットを含める。これにより、一部の日付(DateTime.Nowからの日付など)のみがオフセットでシリアル化されるため、バグの診断が困難になる。ただし、比較演算子はKindを完全に無視する。開発者は、Kindプロパティを自分でチェックし、必要に応じてタイムゾーン変換を実行する必要がある。

これらの問題を解消するために、基本的に.NET 1のDateTimeと同じように機能する新しいDateTimeOnly構造が要求された。

高度なシナリオ

現時点では、実際のタイムゾーンの処理のような高度なシナリオに対処する予定はない。そして、開始と終了から成る期間と長さを表す期間についても同じである。この役割は、主にNoda Timeライブラリによって処理される。JavaのJoda Timeに基づいて、「1月3日」や「2021年3月」など、年、日、月が意図的に欠落している部分的な日付を表すこともできる。

この記事に星をつける

おすすめ度
スタイル

BT