タイムスタンプの精度を落とすときは切り捨てろ

とあるプロジェクトでナノ秒からミリ秒への変換で四捨五入してきた人がいて、時刻を扱うときは保存精度未満は切り捨てるべきというのが常識になっていないなーと思ったので。

2023-10-01 を、何年か表示する時に、2024年に丸める人はいないだろう。 13:45 が何時か表示する時も、13時と表示するだろう。(口頭で何時?と聞かれたら14時と答えるかもしれないけれど)

つまり、ある精度で表した時刻は、実際には次のような半開区間を示しているのである。

  • 2023-01-01 00:00:00 <= 2023年 < 2024-01-01 00:00:00
  • 13:45:00.000 <= 13:45 < 13:46:00.000

そして、そう決めたからには一貫して同じように、指定精度未満は切り捨てというルールを維持しなければならない。秒以下は四捨五入で、とかやってはいけないのだ。

一貫しないと何が問題かというと、精度が異なる区間が綺麗に分割されずにオーバーラップしてしまう。たとえば次の時刻を考えてみよう。

2023-12-31 23:59:59.999555

これは年にすると 2023 年だし、日付にすると2023-12-31だ。 しかしこれをミリ秒で四捨五入すると、 2024-01-01 00:00:00.000 になって、年も日付も変わってしまう。これは、「ミリ秒は四捨五入」というルールを導入したために、 "2024-01-01 00:00:00.000" が表現する時間の範囲が "2023-12-31 23:59:59.999500" <= "2024-01-01 00:00:00.000" < "2024-01-01 00:00:00.000500" になってしまったからだ。

ミリ秒精度のタイムスタンプが示す日時と記録されてる秒単位の日時が一致しない、というような問題を避けるためには、切り捨てにするか四捨五入にするかは一貫しないといけない。日付で切り捨てを採用している限りは、日付未満も切り捨てを採用する以外無いのだ。

以下、実際に幾つかの言語で秒未満の精度でも切り捨てが使われている例を示す。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。