2038年問題とは

こんにちは。
けいぞうです。

今回は「2038年問題」に関する記事です。

※この記事は過去に別のブログで書いた記事のリライトになります。

少々専門的な内容になってしまうので、非エンジニアの方は
2000年問題とは」と「一般向けの説明」だけ読んでもらえれば大体雰囲気は掴むことができるんじゃないかなと思います。

[目次]

2000年問題とは

2038年問題の話題に入る前に、2000年問題について少し触れておこうと思います。


私がまだ子供のこと、「2000年問題」というのが世間を騒がせていたのを覚えています。

その頃父から教えてもらったのは

コンピュータ君はなんとなーく西暦というものを下二桁だけで認識していて

2000年になったらそれが「00」になるもんだから

コンピュータ君は「フムフム、ならば時を戻そう!」

とイカれだしてバグると。

そしてしまいには核ミサイルが発射されて世界が滅びる。

というものでした(トンデモ)


1999年の大みそかの夜のことは今でもよく覚えています。

私は本当に世界が明日滅亡するんだと思い込んでいて、

その日、町が壊滅する悪夢を見たほどです。

2038年問題とは

エンジニア向けの説明

時は流れて2020年。

私は意図せず基幹システムの保守っぽい仕事をしていたのですが、

とある調査中、とあるカラムに「2038年01月19日12時14分7.9999秒」という値がボコボコボコボコ入っているのを見つけてしまいました。


「何だこの中途半端な値は。誰かが何かの対応のつもりで手動で入れたんだな!?」

と思って、騒いでしまったのですが、当時の設計者から

「落ち着け、仕様だ。」
と言われました。


そのカラムはある処理を行った日時を格納するTimestamp型の列(MySQLです)なのですが、
(最終処理日時をセットしておいて、次回処理タイミングなどを決定する)

ある特定の条件に合致したときに最大値をセットして二度と処理されないようにするという仕様だったようです。

それで、MySQLのTimeStamp型の最大値というのが上記の「2038年01月19日12時14分7.9999秒」ということらしいのです。


これって2000年問題の再来じゃん?

二度と処理されないように最大値を入れたのに、2038年1月19日12時14分になったら、再処理されてしまいますよ。

しかもその値が最大値なので、それ以上の値に更新することができなくて、処理が異常終了してしまいますよ。

こういうのを業界では時限爆弾と呼んでいます。

これが、2038年問題です。

一般向けの説明

プログラムが動くときに使うデータをため込んでおく「データベース」というものがあります。

ここには色々な顧客データとか、連絡先とかの個人情報が入っていたりもします。

データベースにデータを登録するとき、大体そのデータと一緒に、いつ登録したか?という日時も一緒に登録します。

登録する日時には様々な形式があるのですが、ある特定の形式は日時が「2038年1月19日」までしか入らない仕様になってしまっているのです。

なので、この日を過ぎると、登録できない形式で登録してしまったり、誤った形で登録してしまったりと、色々と問題が発生してしまうのです。

その色々な問題は、それぞれで作成しているプログラムに依存する部分もあるので、どんな影響があるかを正確に測るのは難しいですが、何もしなければシステムがエラーで動かなくなってしまうのは、確かだと言えます。

最初からこの事実に気づいて設計されていたシステムであれば問題ないですが、

意識せずに作られているシステムであれば、この日を境に動かなくなります。

これが2038年問題です。

安心してください。地球は滅亡しません。

対策について

今回私が見ていたこのシステムではこのTimeStampの最大値がハードコーディングされていました。
もし20年先も運用が続いていたとすると改修が必須になってくると思うのですが、
あらゆるところにべた書きされているので修正モジュールが増えて超めんどいですね。。。。

というわけで対策方法を考えてみました。

これから設計する場合

●TimeStamp型を使わない

まだ設計段階でMySQLを使うことだけ決まっている状況であれば、
TimeStamp型は選択肢から除外してしまいましょう。

2038年問題をいちいち考慮しながら設計するよりも他の道を探った方が楽だろうという考え方です。

例えば、DATETIME型を使う、文字列型にしてyyyy/MM/ddなどのフォーマットを決めるなどです。(何が最適かはケースバイケースですので各々で・・・。)

DATETIME型については、TimeStamp型と違いタイムゾーンの概念を持たない型となっているようです。

つまりTimeStamp型はそのMySQLが動いたローカル環境のタイムゾーンを基準として、その後UTCに変換して格納するとかなんとかその辺の考慮が入っているみたいです。

というかそもそも「タイムスタンプ」という名前からして、この型はそのレコードの更新日時を自動的にセットすることを想定して作られたもののようで、上記システムのように最終処理日時を入れたり最大値を入れたりって使い方自体がTimeStampの設計思想から外れていた、ということになります。

DATETIME型はそんなのないです。グローバルに共通展開しているシステムとかでなければ普通にDATETIMEで良かったんです。

もう稼働しちゃってる場合

●諦めて改修する

最もあるべき姿に改修するのであれば、列の定義をDATETIMEなどに変えることです。

しかし、実際にこの選択肢を選ぶお客様がいたとしたら、それはお金と時間が余っている超優良()企業とかでしょうね。

改修インパクトがデカいですし、リグレッションテストもクソめんどいです。
ちゃんとお金くれるんならやりますっていう程度です。

想定される対応は
・DBの列定義変更
・すでに挿入されてしまっている最大値のデータ更新
・アプリ側の改修
 - TimeStampの最大値をセットしていたりする場合はDATETIMEの最大値に変更する
 - TimeStampの最大値判断をしている箇所があれば、DATETIMEの最大値に変更する
 - などなど・・・
 列定義変更もデータ補正もちょっと考えただけで面倒くさいです。
まずデータが入ったままの状態で列定義変更できない可能性があるので(検証していないので知りませんが)、

別テーブルとして作成してデータを丸っとお引越しした後に元テーブルを削除する感じになるんでしょうか。

とかとかでこの選択肢は無いですね。

じゃあ稼働しちゃってたらどうしたらいいのか

実はこの記事を最初に書いたのは1年前のことで、だいぶ時間がたったのですが、1年経って気が付きました。

小手先で対応できる応急案は無いんだと。

やっぱり結局おとなしく改修するしかないですね。

あと18年も続くシステムなんてそうそう無いでしょうし、大丈夫ですよ、きっと・・・・。