時間の扱いについて、自分が意識していることやよくやっていることを簡単にまとめておく。
時刻と時間
時刻は点で時間は長さを持った区間。
広義の時間について話すときにはこの2つを区別するのがスタート地点。
時間のデータ保持方法
時間は区間なので、始点と終点があり、長さが存在する。
終点 - 始点 = 長さ
であり、3つのうち2つが決まればもう1つは導出できるため、基本的には用途に応じて2つを選んで保持することになる。
大抵は (始点, 終点)
の組み合わせか (始点, 長さ)
の組み合わせになるはず。(長さ, 終点)
の組み合わせは今のところ見たことがない。
検索性などの都合で3つとも保持する場合もあるが、その場合は整合性に注意を払う必要がある。
時間の始点と終点
基本的には始点を含み終点を含まない区間、つまり左閉右開の半開区間 始点 ≤ t < 終点
とする。
終点を含めてしまうと以下のような問題が発生する。
19:00
という時刻が18:00-19:00
と19:00-20:00
という2つの時間のうちどちらに属するのか定まらなくなる or 複数に属することになってしまう18:00-19:00
と19:00-20:00
というような時間同士の重複判定をする際に19:00
という点で重複してしまう- カレンダーアプリで予定の重複判定をするケースなどを想定すると困ることがわかりやすいと思う
時間という(少なくとも実用上)連続なものを切断しているので半開区間になりますよという話。
日付の始点と終点
余談だが、日付の範囲を定義するときは 始点 ≤ d ≤ 終点
という閉区間として定義した方が便利なことが多い。
もちろん 始点 ≤ d < 終点
という半開区間としても良いが、「1月1日から1月3日まで」に1月3日を含まないという解釈は日常的な感覚からは離れているように思う。
日付も広義の時間ではあるが、離散値になるので扱いがちょっと変わるという話。
日付を持たない時刻・時間
適切なクラスがない場合は Clock
のようなクラスをつくって、内部表現としては当日の00:00:00からの経過秒数 0 ≤ t < 86400
で表現することが多い。
永続化の際には経過秒数をそのまま整数で永続化している。
文字列表現
API のリクエストやレスポンスに日付・時刻データを含める際には基本的には RFC 3339 か ISO 8601 を使っておけば良い。独自形式やめて。
誤解を恐れずに言えば、上記の2つはだいたい同じ。自分が気にしている主な違いは以下の2つ。
- ISO 8601 は期間を表せる
2021-01-01T00:00:00+09:00/2021-01-04T00:00:00+09:00
のようにスラッシュ区切りで書ける- 普及して欲しいと思っている表記法のひとつ
- スラッシュが入っていて URL に使いにくいのが難点
- ISO 8601 には
24:00:00
がある- 同じ時刻の表現方法が複数ある(一意に定まらない)
- 24時という表記が欲しい気持ちはわかるし、先述の
Clock
クラスを自作するときには(日付の概念がない都合もあって)大抵扱えるようにしている
RFC 3339 にせよ ISO 8601 にせよ、コンピュータのための文字列表現なので、人間向けの文字列表現は適宜よしなに。ただし、管理画面とかだと(特に日付は)上記形式で済ませてしまうこともある。