ソフトウェアにおける日本時間のズレ

日本時間(JST)の時差は世界標準時(UTC)+9時間である。日本は国内時差は無いしサマータイムも採用していないので、それだけ覚えておけば大丈夫。

と思っていたのだが、この度そうでないことを知った。切っ掛けはWindowsのASPで動くバックエンドとChromeブラウザ間でUNIX時刻でやり取りをしていたとき。明治生まれの人の誕生日が微妙にずれる時があるのだ。

日本時間のブレ

調べた結果、日本時間は次の2パターンで+9時間でない場合がある。

1)~1888年
今の日本標準時が設定されたのがこの年(明治21年)だそうだ。ということはこれより前は日本時間自体が存在しないわけだが、システムによっては+9時間18分が採用されている。

2)1949年~1951年の夏
この時期は日本でもサマータイムが導入されていたらしい。なのでこの年の夏季はUNIX時刻も1時間ずれる。

環境による違い

例えばChromeブラウザでJavascriptを動かすと、上記の通りの結果が返ってる。

> new Date(1887, 0, 1, 0, 0, 0)
Sat Jan 01 1887 00:00:00 GMT+0918 (日本標準時)

> new Date(1950, 7, 1, 0, 0, 0)
Tue Aug 01 1950 00:00:00 GMT+1000 (日本標準時)

それぞれ+9時間18分、+10時間のタイムゾーンになっている。

今度はWindows PowerShellでやってみる。

> ((Date "1887/1/1") - (Date "1887/1/1" -AsUTC)).ToString()
09:00:00

> ((Date "1950/8/1") - (Date "1950/8/1" -AsUTC)).ToString()
09:00:00

両方ともUTCとの時間差は+9時間となっている。

ChromeブラウザやLinuxなどはタイムゾーンの設定をパブリックなデータベースの「tz database」から取得している。一方でWindowsの場合はMicrosoftが管理する時差データを使っている。Microsoftのデータベースでは上記2ケースの例外は考慮していないようだ。

各ミドルウェアやフレームワークがどうしているはそれぞれのようだ。ものよってはUNIX時刻0(=UTC 1970/1/1 00:00)より前の日時は無保証としているものもある。

.Net Core などはOSからタイムゾーン情報を取得しているため、同じプログラムでも実行時の環境によって差が出る。以下は.Net Core3.1で作成したテストプログラムとその実行結果だ。共にOSのタイムゾーン設定はAsia/Tokyoである。

using System;
using System.Diagnostics;

class Program
{
    static void Main(string[] args) {
        var today = DateTime.Today;

        WriteDate(today.Year, today.Month, today.Day);
        WriteDate(1868, 1, 1);
        WriteDate(1888, 1, 1);
        WriteDate(1950, 8, 3);
    }

    static void WriteDate(int y, int m, int d) {
        var jd = new DateTime(y, m, d, 0, 0, 0, DateTimeKind.Local);
        var ud = jd.ToUniversalTime();

        var diff = new DateTime(jd.Year, jd.Month, jd.Day, jd.Hour, jd.Minute, jd.Second, DateTimeKind.Utc) - ud;

        Console.WriteLine($"JST:{jd:yyyy/MM/dd HH:mm:ss}   UTC:{ud:yyyy/MM/dd HH:mm:ss}   ({diff})");
    }
}

実行結果(RedHat)

JST:2022/11/20 00:00:00   UTC:2022/11/19 15:00:00   (09:00:00)
JST:1868/01/01 00:00:00   UTC:1867/12/31 14:42:00   (09:18:00)
JST:1888/01/01 00:00:00   UTC:1887/12/31 14:42:00   (09:18:00)
JST:1950/08/03 00:00:00   UTC:1950/08/02 14:00:00   (10:00:00)

実行結果(Windows)

JST:2022/11/20 00:00:00   UTC:2022/11/19 15:00:00   (09:00:00)
JST:1868/01/01 00:00:00   UTC:1867/12/31 15:00:00   (09:00:00)
JST:1888/01/01 00:00:00   UTC:1887/12/31 15:00:00   (09:00:00)
JST:1950/08/03 00:00:00   UTC:1950/08/02 15:00:00   (09:00:00)

というわけで開発機(Windows)と運用環境(Linux)で差が出てしまったという話。

コメント