ari23の研究ノート

メーカ勤務エンジニアの技術ブログです

2036年問題の解説とその解決策

以前の記事で取り上げたNTPにまつわる、2036年問題について取り上げます。
なお、過去記事は以下にURLを貼っておきますので、よろしければそちらもご覧ください🐜

桜時計で立てたSNTPサーバから、有線LANで時刻取得するときの設定方法 - ari23の研究ノート

NTPと2036年問題とは

Network Time Protocolの略称で、時刻同期のためのプロトコルです。
世界にはNTPサーバというものがあり、協定世界時(UTC)を送信してくれます。

NTPサーバが送る時間は、1900年01月01日00時00分00秒からの積算秒数です。
なぜこの時間を起点にしたかは特に理由がないようですね。
受信側はこの積算秒数をもらって、現地時間にしたり、暦に変えたりして、時刻同期をします。

ただし、この積算秒数は32ビット整数で送られるため、将来オーバーフローしてしまう問題、いわゆる2036年問題があります。

2036年問題の解決策

アプローチとしては2つあります。

  • NTPサーバが送信するデータを64ビット整数にする
    64ビット整数にすれば、西暦3000億年くらい使えるため、根本的な解決になります。

  • 受信側でうまくやる
    オーバーフローしたら、過去の1900年に戻るのではなく、受け手側で未来の時間として理解します。

前者の方がスマートなアプローチですが、実際は後者の方法を取るようです。

受信側の対応

まずオーバーフローする現象を整理し、理解した上で受信側の対応方法を述べます。

オーバーフローする現象

NTPサーバが送る秒(HEX)を、ビットと暦時刻にして整理します。1

秒(HEX) 秒(BIN) 暦時刻
0x00000000 0000 0000 0000 0000 0000 0000 0000 0000 1900年01月01日00時00分00秒(UTC+0)
0x7fffffff 0111 1111 1111 1111 1111 1111 1111 1111 1968年01月20日03時14分07秒(UTC+0)
0x80000000 1000 0000 0000 0000 0000 0000 0000 0000 1968年01月20日03時14分08秒(UTC+0)
0xffffffff 1111 1111 1111 1111 1111 1111 1111 1111 2036年02月07日06時28分15秒(UTC+0)

上記の表を見ると、2036年にオーバーフローを起こし、過去の1900年に戻ってしまうことがわかります。

具体的な対応方法

この記事を書いているのは、2020年で日本では令和2年です。一方1900年は、明治33年で日露戦争前です。

タイムマシンに乗って、2019年の製品を1900年代に持ち込んで使う(ナニに?w)ことはないので2受け手側で読み替えてしまおうというのが、実際の対応です。3

やり方は簡単で最上位ビットで判定します。

秒(HEX) 秒(BIN) 暦時刻
0x80000000 1000 0000 0000 0000 0000 0000 0000 0000 1968年01月20日03時14分08秒(UTC+0)
0xffffffff 1111 1111 1111 1111 1111 1111 1111 1111 2036年02月07日06時28分15秒(UTC+0)
0x00000000 0000 0000 0000 0000 0000 0000 0000 0000 2036年02月07日06時28分16秒(UTC+0)
0x7fffffff 0111 1111 1111 1111 1111 1111 1111 1111 2104年02月26日09時42分23秒(UTC+0)

これにより、2104年まで現行のNTPでも使えるようになります。

おわりに

時刻同期のAPIを開発しているときは、「NTPサーバから64ビットで時間欲しいなぁ」と思いました。
しかし、こうやって整理すると68年も持つんだから、この解決策でもいいのかと考えるようになりました。
世界にあるすべてのNTPサーバの仕様を変更するのは、かなりコストがかかってしまいますもんね。

参考になれば幸いです(^^)


  1. ビットに慣れていないため、すごく丁寧に書きました。

  2. 仮に1900年代に持っていったとしても、NTPサーバもネットもないw

  3. RFC2030に対処法の記述があります。