オリンピックに合わせて?サマータイム導入という話が持ち上がりましたが、無事に収束して何よりです。
ところで、もしサマータイムが実施されていたら、時間を扱うプログラムはどのような影響があるのでしょうか?
サマータイム対応仕様を考えてみる
例として、以下のようなソフトウェアを考えてみます。
勤怠管理みたいなやつです。
開始から終了までは9時間ということがわかります。
終了が開始より前の場合、翌日とみなします。
この場合は深夜0時をまたいだ時間を返します。
ロジックはこんな感じでしょうか。
function get_timespan(開始時間, 終了時間) { if (開始時間 > 終了時間) { return 終了時間 + 24時間 - 開始時間; } else { return 終了時間 - 開始時間; } }
日付は入力できますが、計算には関係ありませんね。
ところで、このプログラムは1日が24時間であることが前提になっていますが、サマータイムが実施されると、この前提が崩れます。
日本で実施されていたサマータイム
日本では戦後の一時期にサマータイムが実施されていましたが、GHQによる占領統治の終了とともに、廃止されました。
https://ja.wikipedia.org/wiki/夏時刻法
- 1948年(昭和23年) - 五月の第一土曜日の翌日(日曜)から九月の第二土曜日まで
- 1949年(昭和24年) - 四月の第一土曜日の翌日(日曜)から九月の第二土曜日まで
- 1950年(昭和25年) - 五月の第一土曜日の翌日(日曜)から九月の第二土曜日まで
- 1951年(昭和26年) - 五月の第一土曜日の翌日(日曜)から九月の第二土曜日まで
- 1952年(昭和27年)以降 - 廃止
どのようなものだったかは、Unixのdateコマンドで確認することができます。
$ date --date='1951/05/05 09:00:00' 1951年 5月 5日 土曜日 09:00:00 JST $ date --date='1951/05/06 09:00:00' 1951年 5月 6日 日曜日 09:00:00 JDT
1951年5月6日を境にJSTからJDTに変わっていますが、この日が夏時間への切り替えが行われた日です。
もう少し詳しく見てみましょう。
$ date --date='1951/05/05 23:59:59' 1951年 5月 5日 土曜日 23:59:59 JST $ date --date='1951/05/06 00:00:00' date: `1951/05/06 00:00:00' は無効な日付です
「無効な日時です」と怒られてしまいましたが、夏時間開始と同時に時計を1時間進めるため、この日の0時から1時は存在しません。
1951/05/05 | 1951/05/06 | |
23:00〜23:59 | 1:00〜1:59 | 2:00〜2:59 |
次は夏時間終了の日です。
$ date --date='1951/09/08 23:59:59' 1951年 9月 8日 土曜日 23:59:59 JDT $ date --date='1951/09/09 00:00:00' 1951年 9月 9日 日曜日 00:00:00 JST
1秒しか進んでいないように見えますが、実は1時間(と1秒)が経過しています。
1951/09/08 | 1951/09/09 | ||
23:00〜23:59 | 0:00〜1:59 | 0:00〜1:59 | 1:00〜1:59 |
9月9日に0時が2回出現しています。
最初のほうが夏時間0:00JDTで、次が0:00JSTです。
どうやら日付と時刻の指定だけではどっちの0時か区別がつかないようです。
もう一度仕様(と設計)を考えてみる
夏時間チェックボックスとエラーチェックを追加しました。
UTCとローカルタイム
こういう場合には、内部処理はすべてUTCに変換して計算すると決まっています。
.NETの場合、DateTime構造体のメソッドを使います。
DateTime 開始UTC時刻 = 開始時刻.ToUniversalTime(); DateTime 終了UTC時刻 = 終了時刻.ToUniversalTime(); TimeSpan 時間 = 終了UTC時刻 - 開始UTC時刻
さいごに
サマータイムは関係なくても、複数のタイムゾーンで使う可能性のあるアプリケーションは、内部処理はUTCにしておかないと後が大変です。