サマータイム
Daylight Saving Time
サマータイムに関する誤解
x サマータイムと言えば通じる。
○ サマータイムは和製英語。英語圏だと Daylight Saving Time と言わないと通じない。
× サマータイムは1時間ずれる。
○ サマータイムは必ずしも1時間とは限らない。
× サマータイムは0時から施行される。
○ 何時から施行されるのかは政府の決定による。
× サマータイムは0時には施行されない。
○ 何時から施行されるのかは政府の決定による。
日本では、5月第1土曜日24時(日曜日1時)にサマータイムに入り、9月第2土曜日25時(日曜日0時)でサマータイムが終わった。
× サマータイムが実施されているときには、サマータイム導入国はどの国もサマータイムである。
○ 国ごとあるいは地域ごとに実施状況が異なる。
○ 南半球では季節が逆になっているので注意が必要。
× サマータイムは夏(8月あたり)に実施される。
○ 事実上夏に実施されているが、政府がいつからどれだけ行うのかを決定するので、夏とは限らない。
○ 南半球では季節が逆になっているので注意が必要。
× 時差とタイムゾーンは同じ意味である。
タイムゾーンは時差が適用される地域を指している。
サマータイムの時には時差が変わる。
タイムゾーン名はサマータイムで変わることがあるが、タイムゾーンは変わらない。(ややこしい)
× サマータイムは時差と同じようなものである。よって、過去でも未来でも現在と同じ時間差で通用する。
○ 過去のサマータイムは実際の実施結果を見ないと分からない。未来のサマータイムは予定分までしかわからない。
絶対時刻が必要なのか、暦としての時刻が必要なのかの区別が必要。
× 日本ではサマータイムは実施されていない。
サマータイムで何が問題か?
サマータイムで時間を早めると、以下のような現象が起こる。
開始日に、サマータイムで早めた分、時刻が飛ぶ。
現地時刻03:00から1時間のサマータイムが開始とすると、その当日だけ 03:00~04:00 の時間がなくなる。
終了日に、サマータイムで早めた分、時刻が二回繰り返される。
現地時刻03:00(サマータイム込み)から1時間のサマータイムが終了とすると、その当日だけ 02:00~03:00 が2回繰り返される。
この場合、その期間の時刻が、サマータイムありかなしか、どちらの時刻か分からなくなる。(ゾーン名、あるいは時差が付いていないと分からない。)
終了時刻が繰り上げ時間により前日に戻ってしまう場合が理論上考えられる。
例えば 10月1日00:00(サマータイム込み)で1時間のサマータイム終了と仮定すると、9月30日23:00に戻ってしまう。
実際にはサマータイムの切り替えは深夜の就寝時間帯(おおよそ2時から4時)に行われるので回避されている。
タイムゾーン名を指定したときに、サマータイムを適用すべきかどうかが実は曖昧。
サマータイムの時にはサマータイム用のタイムゾーン名というのがある。(例: 米国東部標準時ESTと米国東部標準時(夏時間)EDT)
一方、明確に「サマータイムを適用しない」と指定する通常のタイムゾーン名は存在しない。
このため、普通のタイムゾーン名だと、サマータイムは自動的に適用されてしまう。
もしも通常のタイムゾーン名をサマータイム適用なしと見なしてしまうと、今度はサマータイムの自動切り替えが働かなくなってしまう。
つまり、サマータイムを適用しないなら、UTC+時差でタイムゾーンを指定する以外方法がない。
UTC+時差方式であればサマータイムは絶対に発生しない。
しかしそんなことをするくらいであれば、最初からUTCにしておけば混乱は少ない。
サマータイムをどうやったらまともに取り扱えるか?
サマータイムを真面目に実装するならば、必ず基準時刻として、UTCか、明確な時差付きのローカル時刻か、タイムゾーン付きのローカル時刻を記録しなければならない。
タイムゾーン付きというのは、どのタイムゾーンで見た時刻なのか、また、サマータイムを実施した上での時刻なのかそうでないのかの判別のために必要。
安全: タイムゾーン付きローカル時刻→UTC→タイムゾーン付きローカル時刻
危険: タイムゾーン付きローカル時刻→タイムゾーンなしローカル時刻(サマータイムでずれる可能性あり)→タイムゾーン付きローカル時刻(元に戻らない)
「タイムゾーン付きローカル時刻」のように見えて、内部的にはUTC時刻を記録しておいて、見るときにシステムのローカル時刻に変換しているだけ、という実装がある。(これが混乱を引き起こす。)
何が問題かというと、どのタイムゾーンなのか(あるいはその時の時差)を記録していないこと。
システムのタイムゾーンを切り換えると、システムのタイムゾーンの時刻として取得されてしまう。
判別のためには、システム(あるいはセッション)のタイムゾーンを切り換える方法がある。
タイムゾーン付きローカル時刻の問題
タイムゾーンの記録のための容量が必要
タイムゾーン変換がUTCに比べて余分にかかるため少しパフォーマンスが落ちることがある。
よくない実装について
× 日本だから9時間足しておく。(あるいは引いておく。)
△ 日本ローカルでサマータイム対策をしなくてもいい前提であれば。
× サマータイムフラグを別に用意して足し引きする。
△ 例外的に、運用上は切り換えタイミングがずれてしまうことがあり、必要になることもある。
× 自力で表を作ってサマータイムを計算する。
一番信用できるデータベースが tz database であり、一番信用できるのが標準の時刻ライブラリである。
通常は OS レベルで実装されている。
実装メモ
ISO 8601
ローカル時刻+時差。タイムゾーン情報は時差のみ。時差0(Z)は UTC と等しい。
具体的なタイムゾーンが分からないので、単体で見ても、サマータイムの有無までは分からない。
Excel
ローカル時刻。タイムゾーン情報保持なし。
Java
java.util.Date
内部UTC時刻。外部ローカル時刻。タイムゾーン情報保持なし。
java.util.GregorianCalendar
内部ローカル時刻。タイムゾーン情報は時差のみ。
java.sql.Timestamp
java.util.Date にナノ秒のプロパティを追加したもの。無理矢理つなげたものなので色々不都合あり。
内部UTC時刻。外部ローカル時刻。タイムゾーン情報保持なし。
HTML
デフォルトで現在時刻が出るかもしれないが、単純に時刻を文字列として受け取るのみで、サマータイムまで考慮されていないはず。
単純に時刻を文字列として受け取るのみで、それ以外の機能を持たない。
JavaScript
Date
内部UTC時刻。外部ローカル時刻。タイムゾーン情報保持なし。
getTimezoneOffset は現在時刻とUTC時刻との差。Date オブジェクトの中にある時刻とは異なる。
UTC付きの関数を使うとUTCで扱える。それ以外はローカル時刻
JSON.strigify() では toISOString() した結果が出力される。(通常は UTCで時差0)
https://gyazo.com/77ad81882dd4d737db43ec4810ba416b
PostgreSQL
timestamp without time zone 型
ローカル時刻。タイムゾーン情報保持なし。
timestamp with time zone 型
内部UTC時刻。外部ローカル時刻。タイムゾーン情報保持なし。
C言語
time_t 型
ISO C
実装依存。シリアル値であることが想定されている。
POSIX
整数値であることは決まっているが、それ以上は決まっていない。
多くの POSIX 準拠システム
1970-01-01 00:00:00 UTC からの経過秒数(精度は秒)
struct tm
tm_isdst フラグで夏時間かそうでないかがわかる。時差は分からない。
timezone 変数
POSIX
UTCからの時差を秒数で保持
現在の時差しか保持していない。(過去や未来の時差は分からない)
関数ではなく変数なので定義的に正しくない。
日時関数の挙動
環境変数TZでタイムゾーンが認識される。
環境変数TZを内部的に変えた場合、tzset 関数で認識させなおす必要がある。→ timegm