したがって、短い答えは、Adamが正しいroll
ということです。日付ピッカーや同様のユースケースadd
を処理するために特別に存在し、月と年を処理するために特別に存在Duration
します。開始点を知らずにナノ秒)。しかし、それが物事を明確にする場合に備えて、より詳細な答えを突き刺します。
DateTime
、Date
、およびTimeOfDay
は、カレンダーベースの操作用に設計されています。システムクロックとは関係がなく、タイムゾーンの概念もありません。また、日付/時刻の部分を個別の単位 (年、月、日、時間など) として内部的に保持します。したがって、hour
フィールドを に設定するDateTime
と、文字通りDateTime
のメンバー変数の 1 つを調整するだけです。そして、Duration
それらに a を追加する場合、それを分割して各ユニットに個別に追加する必要があるためDuration
、7 時間の a を追加するなどのことを行うと、フィールドだけでなく増加する可能性がありhour
ます。例えば
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt += hours(7);
assert(dt == DateTime(2015, 8, 3, 3, 0, 0));
また、Duration
その値は内部でヘクトナノ秒単位で保持されるため、必ずしも特定の単位に追加する必要はありません。つまり、具体的にフィールド+= hours(7)
に追加するようなものではありません。hour
全体に数ヘクトナノ秒を追加してDateTime
おり、特定のユニットに影響を与えるのではなく、各ユニットにどのように影響するかを把握する必要があります。例えば
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt += hours(7) + minutes(5) + seconds(22);
assert(dt == DateTime(2015, 8, 3, 3, 5, 22));
roll
一方、他のユニットに影響を与えずに特定のユニットに追加するためのものです。Adam が正しく判断したように、その主な使用例は、特定の時間単位をある程度調整することになる日付ピッカー ダイアログのスピン コントロールなどであり、他の単位には影響を与えたくないので、あなたは微調整しています。したがって、7 時間を追加すると、1 日が増えるのではなく、時間だけが増えます。
auto dt = DateTime(2015, 8, 2, 20, 0, 0);
dt.roll!"hours"(7);
assert(dt == DateTime(2015, 8, 2, 3, 0, 0));
ここで、月と年は長さが固定されていないため、物事は少し面白くなります。Duration
そしてそれが彼らをサポートしない理由です。x
ヘクトナノ秒がy
月やz
年に相当するとは言えません。ただし、Duration
月または年に関しては意味がありませんが、Date
orに月と年を追加できるようにしたいと考えていますDateTime
。そのため、これを処理する必要がadd!"years"
ありadd!"months"
、1 月 31 日に 1 か月を追加すると、2 月末になるか 3 月初めになるか (2 月 31 日がないため) など、いくつかの奇妙な点を制御できます。
これには、いかなる種類のタイムゾーンも考慮されていません。純粋にカレンダー時間を扱っています。add
とroll
は純粋にカレンダーベースの操作であり、 、 、およびに実装+=
されているように、はカレンダーベースの操作です。計算を行う際に、年、月、日などを考慮に入れています (単位はメンバー変数間で分割されているため、この場合は別の方法では実行できません)。DateTime
Date
TimeOfDay
そして、私たちは持っていSysTime
ます。これは、システムの時刻を表すことを目的としています (これは、タイム ゾーンを考慮に入れることを意味します)。ただし、DST 関連の問題などを回避する唯一の方法は、時刻を常に UTC に保つことです。そのため、SysTime
常に内部的に UTC (ヘクトナノ秒単位) で時刻を保持し、TimeZone
オブジェクト (LocalTime
既定では) を使用して、必要な場合にのみそれを特定のタイム ゾーンに変換します。これにより、あらゆる種類の厄介な時間関連のバグが回避されます。また、システムの時間で操作している人は、 、、またはSysTime
ではなくを使用する必要があります。DateTime
Date
TimeOfDay
したがって、SysTime
usingに追加すると、実際にはからのヘクトナノ秒を内部で使用するヘクトナノ+=
秒に追加するだけです。カレンダー操作はまったく行われません (もし行われたとしても、多くの DST 関連のバグが発生することになります)。本質的にカレンダーベースではありません。カレンダー操作を行うには、内部で保持されている a のヘクトナノ秒を、グレゴリオ暦の日付で表すものに変換する必要があります (オブジェクトを使用して、タイム ゾーンを考慮します)。Duration
SysTime
SysTime
SysTime
TimeZone
ただし、ユーザー フレンドリにするためにSysTime
、カレンダー ベースのプロパティと機能の多くを提供しますDateTime
(たとえば、、、、year
などmonth
のday
プロパティhour
とadd
およびroll
関数)。それをサポートするために、基本的に変換するDate
か、DateTime
内部的にそれらを実行することになります。これは、タイムゾーンを考慮に入れることを意味し、正しく使用されないと DST バグが発生する可能性があることを意味します。また、場合によっては、厄介なほど非効率的です。たとえば、次のSysTime
変数があるとします。st
auto year = st.year;
auto month = st.month;
auto day = st.day;
は 3 回に変換st
されますが、明示的に に変換してそこから単位を取得Date
する方が効率的でした。Date
したがって、その使いやすさは少し両刃の剣です。
また、Adam が DST をどのように追加およびローリング処理するかについて提起した問題も提起されます。roll
またadd
、SysTime
両方とも内部でDate
またはを処理し、UTC から変換するか、UTC からオブジェクトが表すものに変換DateTime
するため、DST が考慮されます。したがって、彼らが操作する方法とまったく同じように操作します。SysTime
Date
DateTime
TimeZone
roll
add
SysTime
DateTime
DateTime
しかし、すでに述べたように、+=
onはを UTC 時間にSysTime
追加するだけです。そのため、月未満の単位を追加して DST を考慮するDuration
方法はありません。SysTime
明示的に に変換し、その上DateTime
で使用+=
してから に戻す必要がSysTime
ありますが、これは少し醜いですが、通常必要なものではありません。月よりも小さい単位で作業を行うことができるとSysTime.add
思いますが、そうすると、それを使用している人がいて、DST 関連のバグを使用する必要が+=
あるのに、違いを理解していないということになります。
本当に、この時点で、これらのカレンダー機能を に追加することSysTime
が賢明だったのか、実際には意図したように役立つのではなく、最終的にユーザビリティを害しているのか疑問に思います. しかし、現時点でそれを変更できるとは思えません。より正確には、変更することはできますが、これらの機能を非推奨にしSysTime
、人々にコードの変更を強制することは、それが引き起こす苦痛に見合う価値があるかどうか疑問に思います. やり直せるなら、カレンダーベースの操作を に置かないことを真剣に検討しSysTime
ます。
いずれにせよ、うまくいけば、そのテキストの壁はあなたの時間の価値があるほど十分に啓発的でした.