datetime

日時データの何がめんどくさいのか


ネタ元というか発端

【新元号】改元のシステム改修で慌てるシステム屋は「無能」とのこと


入力と表示だけの話ではない点

このセクションは和暦や改元とはまったく関係ないです。でも一応触れておく必要があると思ったので。

今では日時の内部データがUnixTimeやユリウス日などの「ひとつの数値」として扱えるし、ライブラリなども充実しているのでそれほど厄介なことはないです。

それでも「表示や入力だけの問題だろ」は違うよ、という話。


  • ソート: 日付順にソートする必要があることはそんなに珍しくないよね


  • 範囲指定: 「〇年〇月のデータ一覧」とか「過去〇日分の一覧」みたいなの


  • 日数計算: 「有効期限〇日」とか金利計算とかで、ある日付からもう一つの日付までの期間の長さを知りたい場合はけっこうある


範囲指定や日数計算は今でも厄介な罠が潜んでいて「月の日数に違いがある」「うるう年のために年の日数にも違いがある」というのはけっこう面倒。

2月25日に「過去一か月分」といったら何日前までのデータが来ることを期待しますか?2月だから(うるう年でなければ)28日分?それとも1月25日~2月24日までの31日分?

一応ライブラリなどではルールを決めているので、細かいこと気にする必要がなければDateTime.Now.AddMonth(-1)などと書けば「一か月前の日付」を得ることができるんだけど、ライブラリ内部ではそういうめんどくさいことも気にして計算ルールを作っています。

そういう便利なライブラリがなかった時代や、ライブラリの採用しているものとは違う計算ルールを使う必要がある場合などは独自に実装する必要があり、けっこう慎重に設計していないとおかしなことになってたりします。

あと「5分しか経ってなくてもその間に日付が変われば1日経過、23時間経ってても日付が変わってなければ0日」みたいな計算はわりとあります。

このとき内部で保持している日時がUTCだと「ローカルタイムに変換してから"日"未満の端数を切り捨てた数字同士で日数計算」みたいなことが必要になります。


「年」「月」「日」「時」「分」「秒」を別フィールドに持つ日時形式

CPUが8bitや16bitの時代は日時を「ひとつの大きな数字」として扱うのはビット数が長くなるので大変でした。

計算速度も遅いのでその大きな数字を割り算して年月日…などに分解するのを表示のたびにやってたら遅くて実用にならない。

だから年月日などを別々のフィールドとして記録する方が一般的でした。

たとえばCP/MやMS-DOSのファイルタイムスタンプ。Windowsの時代になってもBIOSはIBM-PC由来のレガシーAPIだったのでやっぱりRTCは年月日時分秒が別フィールド。ようやくUEFIになってその過去を捨てられました。

そのため古いプログラムではファイルシステムやBIOSと同じように年月日別フィールドは割と当たり前にありました。

さすがにデータベースシステムは比較的早いうちから内部形式としては「ひとつの大きな数字」として持っていたみたいだけど、PC用のローカルデータベースではパフォーマンスの問題などで年月日形式のもあったと思います。


そこに和暦が入ってくると

年月日別フィールドは日数計算などでかなりめんどくさいことになって、さらに2000年問題でやべーことになったわけだけど、それでも西暦で持っていれば「年の数字が大きい方が新しい日付」となるのでまだシンプルです。

ところがいろいろ事情はあったのだろうけど「年号」「年」「月」…といった内部形式が和暦なデータも存在したりします。

「年号は年より上の桁」と解釈すれば年以下の大小関係は維持されるのでまだいいんだけど、年号同士の大小関係は人間が指示しないとコンピュータにはわかるわけない。これが和暦ハードコーディングの温床のひとつです。

とはいっても「それぞれの年号に番号を振ってその番号でソートすればいい」という解決策はある。実際.NET Frameworkの和暦カレンダーなどではそういう方法を取っています。

でも年号と番号の対応付けには標準的なルールは存在せず、システムローカルな対応付けでしかありません。

それに3つか4つしかない年号のために対応表を用意するのも冗長と考える人も多かっただろうから、年号は文字列として持っていてソートや日数計算に必要な大小関係はハードコーディングで対処しているものも少なくないです。


データの内部形式を変えるのはかなり大変

そういうシステムの改元対応の仕事が回ってきたらそんなシステム作った人を呪いたくなるだろうけど、そのシステムが使えなくなったら困る人がいるからそういう仕事が来るわけで、がんばってなんとかするか逃げ出すかくらいしかないでしょう。

そのシステムで扱ってるデータは「年月日別フィールド」。根本的に解決するなら日時データをすべてユリウス日やUnixTimeなど今どきの形式に置き換えたいところだけど、それをするにはシステム内で日時を扱っている箇所すべてを書き換えてテストする必要がある。既存のデータの変換作業も必要です。

そして「そんな大きな変更をする予算も時間もないから、最小限の変更で何とかしてくれ」というパターンもきっと多いはずです。

問題があるシステムだとわかっていても、既存コードが年号の大小関係をハードコーディングしていたらそれに合わせてハードコーディングしないと「最小限の変更」では済まなくなってくることもあるでしょう。


もし改元対応をお願いされたら、まず日時の保存形式を確認しましょう

実際には年月日別フィールドまではありえても、内部形式まで和暦というのはそう多くないはずです。(でも存在する)

それでも古いシステムだと西暦と和暦の変換をしてくれるようなライブラリが存在しなかったため、変換機能はシステム独自にハードコーディングというのは少なくないはずです。

そうなると内部形式を変えられないのであれば、その場しのぎにしかならなくても西暦和暦の変換機能を再実装して、そのついでで将来の改元でも最小限の変更で済ませられるようにする程度でお茶を濁すしかない案件はけっこうあると思います。


個人的には年号がなくなってほしい

別に完全には消滅しなくてもいいので、今の旧暦くらいの存在感になって少なくともオフィシャルな文書関係で「和暦でないとダメ」はなくなってほしいです。

どうせ明治5年以降は月日の部分はグレゴリオ暦なんだし。

実際のところ、昭和のころは西暦より和暦の方が一般的だったんですよ。昭和が何十年も続いてるから大して不都合はなかったからでしょう。

それが平成になって年号をまたぐめんどくささはコンピュータがらみだけではなく「平成5年の7年前って何年?」みたいに日常生活でも微妙に煩わしくなってきたこともあってか、いつのまにか西暦表記の方が一般的になっているんですよね。