2 ポイント 投稿者 GN⁺ 2024-12-27 | 1件のコメント | WhatsAppで共有
  • POSIX time/Unix time は一般に 1970-01-01 00:00:00 以降の秒数と呼ばれるが、実際には うるう秒を無視した UTC ベースの値であり、実際の経過秒数とはずれがある
  • 2024-12-25 18:51:26 UTC 時点では POSIX time は 1735152686 で、epoch 以降の実際の経過秒数は 1735152713 秒となり、27 秒の差がある
  • IEEE 1003.1 は seconds since the Epoch を定義する際、1 日を常に 86,400 秒として計算し、標準の付録でも 1970 年以降に追加された 14 秒のうるう秒を互換性と計算の容易さのために無視している
  • UTC は太陽日との差を小さくするために うるう秒を追加し、このとき POSIX time が後ろにジャンプすることで、Linux、Qantas、Cloudflare DNS などで障害事例が起きた
  • 単一コンピュータでの時間間隔の測定には CLOCK_MONOTONIC または CLOCK_BOOTTIME の方が適しており、POSIX timestamp と合わせる必要があるなら leap smear や POSIX↔TAI 変換を検討すべき

POSIX time は実際の経過秒数ではない

  • JavaScript Date、GNU coreutils、Linux time(2)、Go time.Unix、MySQL datetime、Ruby Time、Cassandra timestamp などは、POSIX time をしばしば Unix epoch 以降の秒数のように扱う
  • しかし、この表現は一般的な直感と正確には一致しない
    • 例の時刻: 2024-12-25 18:51:26 UTC
    • POSIX time: 1735152686
    • POSIX epoch 以降の実際の経過秒数: 1735152713
    • 差: 27 秒
  • この差は、POSIX time が IEEE 1003.1UTC から導出されつつも、すべての日を厳密に 86,400 秒と仮定しているために生じる
  • 標準における seconds since the Epoch の定義は、tm_sectm_mintm_hourtm_ydaytm_year を用いて値を計算し、1970 年未満の年や負の値との関係は定義していない
  • 実際の 1 日の長さは常に 86,400 秒ではなく、時期によって変わる
    • UTC の日付が太陽日から離れすぎないように、天文学者が定期的に うるう秒 を宣言する
    • その結果、POSIX time は数年ごとに後ろへジャンプする可能性がある
    • 将来的には前にジャンプすることもあり得る
  • うるう秒は実際に障害につながったことがある

標準の妥協と実務上の代替策

  • IEEE 1003 付録 B は、標準の発行時点で 1970-01-01 以降に 14 回のうるう秒が追加されていたものの、計算の容易さと互換性のためにこの 14 秒を無視すると整理している
  • 標準は、ほとんどのシステムの “time” 値は増え続けるとみなし、うるう秒の間もこの値が増加すべきだという立場を取る
    • 同時に、ほとんどのシステムはうるう秒を追跡していないか、標準時基準に同期していない可能性があることも前提としている
    • そのため seconds since the Epoch が、参照時刻と epoch の間の正確な秒数を必ず表すことまでは要求していない
    • アプリケーションがこの値を epoch 以降の秒数のように扱えれば十分であり、必要な精度はシステムベンダーと管理者が調整すべきという立場である
  • 分散アプリケーションでは timestamp でイベントを同期するため、一貫した解釈が重要になることがある
    • うるう秒の累積は予測できない
    • epoch 以降のうるう秒の数は増える可能性がある
    • 標準は、天文学的には短い期間におけるアプリケーション間の時間同期をより重視している
  • 実際のシステムは時間が多少ずれてもたいてい動作するが、うるう秒はまれであり、「epoch 以降の秒数」という 線形な直感が強いため、未発見のバグが蓄積する可能性がある
  • 状況別の代替策は次のとおり
    • 1 台のコンピュータで 2 つのイベント間の duration だけを計算するなら CLOCK_MONOTONIC、さらに言えば CLOCK_BOOTTIME を使う
    • POSIX time を前提とする他のシステムと timestamp をやり取りする必要がないなら TAI, GPS, LORAN を使う
    • POSIX timestamp 系のシステムとおおむね合わせる必要があるなら、leap smear でうるう秒をより長い時間区間に分散させる
    • qntm の t-a-i のようなライブラリで POSIX と TAI の間の変換が可能
  • うるう秒を廃止しようとする取り組み が進んでおり、2035 年までに 実現されることが期待されている
    • 1 日 86,400 秒 という仮定に依存するあらゆるものに変換テーブルを入れる追加作業が必要になる
    • 2035 年以降の時刻については、「2 つの時刻の間に何秒あるのか」といった問いがはるかに単純になる可能性がある

1件のコメント

 
GN⁺ 2024-12-27
Hacker Newsの意見
  • Vernor Vingeの2000年のSF小説 A Deepness in the Sky をちょうど読み終えたところだが、epoch以後の秒数(seconds since the epoch)への思いがけない言及が出てくる見事な一節がある
    「Tradersの時間計測方式を見よ…」で始まり、Qeng Hoが人類がOld Earthの月に初めて足を踏み入れた瞬間から秒単位で数えているが、さらに詳しく見ると開始時点は実際には約1,500万秒後、初期の人類のコンピュータOSのひとつにおける0秒だった、という描写になっている

    • この本は個人的に歴代でも特にお気に入りの一冊で、さりげないソフトウェア・リファレンス の使い方が本当に良い
      「宇宙の中のコンピュータサイエンス」をもっと読みたいならBobiverseシリーズを、「人間 + シミュレーション + コンピュータ」の探究をもっと読みたいならPermutation Cityを勧める
  • 時間計測について読むたびに、必ず何か新しく学ぶことがある。Unix時間はロールオーバーだけ考えれば時間を追跡する最も単純な方式だと思っていたし、うるう秒 は知っていたが、これにも適用されるとは考えたことがなかった
    「UTC, GPS, LORAN and TAI」のリンクも読んだが、GPS時間がうるう秒を反映しない点は興味深い対比だ

    • ある出来事が 何秒前/後 に起きたと言うのは単純だ。難しいのは、その時点にカレンダー上の日付を割り当てることだ
    • 結論として TAI が最も単純で、他の形式は必要なときだけTAIから変換して使うべきだと思う。たとえば表示や相互運用性のためだ
  • 「2035年までにうるう秒をなくそうという動きが進んでいる」という計画はあまり気に入らない
    UTCの本質は、TAIから整数秒だけずれていて平均太陽時(MST)に近いことにある。もうMSTを追跡しないのなら、単にTAIへ移行すべきだ
    UTCをMSTから離れていくままにすると、過去のうるう秒は引き続き処理しなければならないのに、そのうるう秒がもはや目的を持たない 中途半端な状態 になる

    • MSTから外れることは、得られるものよりコストのほうが大きいという点には同意する
      ただ、この提案が完全に無意味というわけではない。既存の UTC時刻管理 は変えず、2035年以降の2つのタイムスタンプの差が正確な物理秒数になるようにする、という目的はある
      それでもMSTはすでにUTCの機能なのだから、それを取り除くのはおかしく見える
    • 理想的な世界なら、コンピュータシステムは時間追跡に TAI を使い、TZデータベースを用いてUTCやローカル時刻へ変換すべきだった
      しかし現実には多くのシステムが誤った選択をしており、特にUNIXが最大の原因だ。その選択が無数のシステムや規格に深く組み込まれているため、「単にTAIへ移行する」のは事実上不可能だ
      だからUTCを「新しいTAI」として再解釈するほうが容易だ。いつか昔のUTCが別の名前で再登場しても驚かないと思う
    • TAIという別個の実体 があるわけではない。UTCから出発して、関心のあるうるう秒の数を引けば得られるのがTAIだ。TAIが別個の標準量として維持されているわけではない
      ほとんど、あるいはすべての国で民間の時刻はUTCを基準にしている。少しだけより純粋だという理由で、世界中の時計を30秒ほど後ろへ戻すことはない
      GPS時間にもTAIとのオフセットがあるが、誰もそれほど気にしていない。Unix epochも同じで、結果が一貫していればそれで十分だ
    • ハック自体は文字どおり些細なものだ。月に一度UTC # ETかどうか確認し、違っていれば Leap_Second というファイルを作ればいい。毎月このファイルがあるか確認し、あれば削除してから Leap_Seconds ファイルの値に1を足し、LSSE というバックアップを作ればよい
      「You are not expected to understand this.」両方のシステムを維持するやり方だ。望むならハッシュやルックアップテーブルでも作れる
  • 現代的な UTC epoch が1972年1月1日である点も重要だ。それ以前のUTCはTAIと異なる秒の長さを使っていた
    1971年末には中間段階として、正確に0.107758 TAI秒の最後の不規則なジャンプがあり、1958年から1971年までのUTCまたはTAIの小さな時間ステップと周波数調整の合計がちょうど10秒になるよう調整された。したがって1972年1月1日 00:00:00 UTCは、正確には1972年1月1日 00:00:10 TAIだった。その後は整数秒の差になった
    同時にUTCのティック速度はTAIと完全に同じになり、UTCはUT2ではなくUT1を追跡し始めた。したがって1970年と1971年のUnix時間は、その時期の実際のUTC時刻とは一致しない
    https://en.wikipedia.org/wiki/Coordinated_Universal_Time#His...
    https://en.wikipedia.org/wiki/Unix_time#UTC_basis

    • このため、今日生きている人の中には、自分の 正確な年齢(秒単位) を知ることができず、今後も知ることができない人がいる
      出生証明書の時刻が秒単位で正確だと仮定してもそうだ。その人の生涯の一部では、「1秒の長さ」と見なされていた値が、今私たちが普通に考える1秒と比べてかなり異なっていたからだ
      ここでいう秒とは、セシウム133原子の摂動のない基底状態における超微細遷移周波数 9,192,631,770/s を基準とする秒を意味する
  • 最近ある取引所向けのコードを書いたのだが、そのシステムは VAX、正確には OpenVMS 上で動いており、epoch は 1858年11月17日だった。
    キャリアの中で Unix 以外の epoch を見たのは初めてで、幸い使っていたコードでは Unix epoch に抽象化されていた。

    • 1858年の epoch は、天文学の標準暦である Julian Day に由来するようだ。ここで 0日目は紀元前4713年である。
      https://www.slac.stanford.edu/~rkj/crazytime.txt
      1950年代のコンピュータのメモリにこれらの日付を収めるため、暦を240万日ぶんオフセットし、その結果 0日目が 1858年11月17日になった。
    • Excel の epoch である 1900年1月1日と Basic の 1899年12月31日の衝突に関する、古い Microsoft の逸話もある。
      https://www.joelonsoftware.com/2006/06/16/my-first-billg-rev...
    • 覚えておくとよい、もう1つの一般的なコンピューティングシステムとして、Windows epoch は 1601年1月1日である。
    • クラシック MacOS、Apple の HFS ファイルシステム(OS X でも使用)、PalmOS はいずれも epoch が 1904年1月1日 だった。
      macOS/Swift Foundation API NSDate.timeIntervalSinceReferenceDate は 2001年1月1日を epoch として使う。
      Wikipedia にも便利な一覧がある: https://en.wikipedia.org/wiki/Epoch_(computing)#Notable_epoc...
    • PostgreSQL は内部的なタイムスタンプ保存に 2000-01-01 epoch を使っている。
  • ある時点は POSIX タイムスタンプ では表現できず、また一部の POSIX タイムスタンプは実際の時刻に対応しなくなる。

    • 実際の時刻に対応しない POSIX タイムスタンプとは何か気になる。あるいは将来 負のうるう秒 が発生した場合の話だろうか?
    • これは昔からそうだ。Unix 時間では 1970年以前 は定義されていない。
    • それでも少なくとも、1つの POSIX タイムスタンプが複数の実際の時点に対応することはない。みんなが何にでも使っている、たった1つの表現方式よりはましだ。
    • いや、そうではない。
      それは ISO 8601 に年が存在しない時点があると言うのに近い。すべての時点には年があるが、ある年は他の年より長いだけだ。
      https://time.is/UTC を座って眺めていれば、時間は単調に増加し、ときどきある1秒がほんの少し長くなるだけだと分かる。たとえば 24時間の中で 0.001% ほど長くなる、といった程度だ。
  • データベースに日付を保存するときは、常に Unix epoch 時間 で保存し、日付フィールドにはタイムゾーン情報を記録しない。タイムゾーンを知る必要がある要件があれば、別に保存する。
    その代わり、タイムスタンプを TAI 形式で保存し、必要なときに UTC に変換する関数を使って、地球に関する補正が必要なときに対応できるようにすべきなのだろうか。
    タイムゾーンが地雷原だというのは分かっているが、それも時間の経過とともに境界が変わる人間の構築物だ。絶対時間に固定しておいて、必要なときに望むローカル時刻形式でレンダリングすべきな気がする。

    • その通り。TAI またはそれに類する形式 こそが「システム」時間を追跡する唯一合理的な方法であり、より高位のシステムがそれを人間向けの時刻に変換すべきだ。
      うるう秒の調整はタイムゾーン変換と同じ場所で行われるべきだ。残念ながら Unix が誤ったものを標準化してしまい、移行は難しい。
    • だいたいは違うし、ほとんど常に違う。ほとんどのソフトウェアはうるう秒を押しつぶす前提で書かれていて、実際には時計同期レイヤーでしか発生しない。たとえば chrony はうるう秒スミアリングを実装している。
      したがって、どのみちすべての時計は UTC に合わせられている。保存時に UTC から TAI に変換し、読み出し時にまた戻すことになるので、混乱するだけだろう。
    • 「日付フィールドにタイムゾーン情報を記録しない」という部分について言えば、実際にタイムスタンプカラムで タイムゾーンの保持 を可能にしているデータベースは非常に少ない。
      通常、データベースは保存されたタイムスタンプに対するタイムゾーンの概念を持たないか(SQL Server)、あるいは「タイムゾーン対応」タイムスタンプ型を提供していても入力を UTC に変換して元のタイムゾーンを捨てる(MySQL、Postgres)。
      知る限り、Oracle だけが with time zone 型でローカルではないタイムゾーンを実際に往復保持できる。
    • システムが何を保存するかによる。ほとんどのシステムは、数年に一度 1秒ずれることを気にしない。
      計算によっては 1秒の差が大きな問題になる。最も広く使われている形式ではないものを採用するときは慎重であるべきで、標準から外れるだけの正当な理由が必要だ。単に違うというだけでもコストは大きくなりうる。
    • データベースの ネイティブな日時フィールド を使えばいい。
  • この記事のせいでクリスマスが台無しになった気分だ。神聖なものは何もないのか? 秒とは epoch 以降の秒であるべきだ。
    太陽日から少しずれることを、なぜ気にする必要があるのか分からない。epoch 以降の秒を日付表現に変換するコンバータが補正を担当すればよいのではないか?

    • 今の方式こそが、実際に私たちの望む方式だ。86400秒 = 1日 であり、私たちは UTC の真夜中が常に 86400 の倍数であるという前提で動いている。
      すべてのソフトウェアにうるう秒の導入をハードコードさせ、スミアリングを処理させ、新しいうるう秒が導入されるたびに1か月以内の更新を要求するようなことはしたくない。
      これまでも気にしたり考えたりする必要はなかったし、これからもその必要はない。正しいやり方で処理されている。
  • うるう秒は赤道に取り付けた 大型ロケット で置き換えるべきだ。時計を調整するのではなく、惑星を調整しよう。

    • 計算ミスで地球が遅くなりすぎたり速くなりすぎたりしたら、あまり笑えないだろう。
      イスラム教の伝承における終末とダッジャール(Dajjal)に関する話にも、こうしたことが実際に起こるかのような一節がある。「ダッジャールの最初の日は1年のようで、二日目は1か月のようで、三日目は1週間のようになる」とされ、多くの人はこれを文字どおり、すなわち地球の自転が実際に遅くなり、最終的には向きが反転して太陽が西から昇るような宇宙的出来事として受け取っている。それが人類終末の最後の兆候だ。
  • うるう秒のせいで epoch が date +%s が暗示するより29秒古いとしても、だから何なのかという気がする
    現在時刻を表すある数値 N にみんなが合意しているという事実のほうが、はるかに重要だ。仮想的な -29 秒が現実世界に影響するわけではない。30年前の目標に対してミサイル照準ルーチンを走らせるわけでもないだろう
    うるう秒の廃止には賛成だが、時刻の不一致を強調することが有用だとは思わない。厳密には正しい話だとしても

    • 短い出来事の継続時間を開始時刻と終了時刻から計算する状況は想像できる。その区間がうるう秒をまたぐと、タイムスタンプの扱い方によっては 継続時間 がかなり変わりうる
      より重要なのは未来への影響だ。過去のタイムスタンプが単純な「現在 - N秒」計算と数秒ずれること自体は、たいてい興味深い事実に近いが、将来のある時点で全ての時計がまた1秒ずれなければならないかもしれない、という点のほうが重要だ。これを考慮するには相当な努力が必要になる現実の事例が多い
    • 一部のものにとっては重要だ。そのような仮想的なうるう秒がなければ、たとえば 地方太陽正午 における太陽の位置が29秒分ずれることになる