山崎屋の技術メモ

IT業界で働く中でテクノロジーを愛するSIerのシステムエンジニア👨‍💻 | AndroidとWebアプリの二刀流🧙‍♂️ | コードの裏にあるストーリーを綴るブログ執筆者✍️ | 日々進化するデジタル世界で学び続ける探究者🚀 | #TechLover #CodeArtisan、気になること、メモしておきたいことを書いていきます。

【解決!!!】LocalDate から Date への変換で怪現象

趣味で西暦・和暦変換処理を作っていて不思議な現象にあいました。

LocalDate を Date に変換する必要があったので、ネットで調べたらいくつかのサイトがヒットしました。

String、Date、LocalDateの変換 - Qiita

java.util.Date型にjava.time.LocalDateを変換する java-8 java-time | CODE Q&A [日本語]

簡単なサンプルを試しました。

	public static void main(String[] args) throws Exception {
		LocalDate ld = LocalDate.of(2018, 3, 24);
		Date date = Date.from(ld.atStartOfDay(ZoneId.systemDefault()).toInstant());
		System.out.println(date);
	}

実行結果。

Sat Mar 24 00:00:00 JST 2018

なんの問題もないですね。解決・・・

と思っていたのですが、大昔の変換も行う必要があるので、ひとまず 1850 年で試しました。

	public static void main(String[] args) throws Exception {
		LocalDate ld = LocalDate.of(1850, 1, 1);
		Date date = Date.from(ld.atStartOfDay(ZoneId.systemDefault()).toInstant());
		System.out.println(date);
	}

実行結果。

Mon Dec 31 23:41:01 JST 1849


ずれとるやないかい!!!!!!!!!


いろいろな日付で試してみるとどうやら 1888 年 1 月 1 日以前だと 18 分 59 秒ずれるみたいです。1888 年 1 月 2 日だとずれません。

ググってみたけれど同じ現象で困っている人は見つけられませんでした。

とりあえず、いったん文字列に変換することで、怪現象を回避した処理は作れたので、原因は継続調査ということにしておきたいと思います。

Java はちょっと古めの 1.8 です。詳細は下記参照。

C:\Users\yyama>java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

もう気になって夜しか眠れません。

解決したら追記します。


以下、2018 年 5 月 19 日追記

解決しました!!!

コメント欄に fog_og_frog2 様より情報をいただきました。

tz databaseの1888年以前の時差は2秒ずれてる? - きしだのはてな

引用:

Transition[Overlap at 1888-01-01T00:18:59+09:18:59 to +09:00]
Transition[Gap at 1948-05-02T02:00+09:00 to +10:00]
Transition[Overlap at 1948-09-11T02:00+10:00 to +09:00]
Transition[Gap at 1949-04-03T02:00+09:00 to +10:00]
Transition[Overlap at 1949-09-10T02:00+10:00 to +09:00]
Transition[Gap at 1950-05-07T02:00+09:00 to +10:00]
Transition[Overlap at 1950-09-09T02:00+10:00 to +09:00]
Transition[Gap at 1951-05-06T02:00+09:00 to +10:00]
Transition[Overlap at 1951-09-08T02:00+10:00 to +09:00]

一番上の行にあるとおり、1888 年 1 月 1日に UTC +09:18:59 から UTC +09:00:00 に変更された記載が読み取れます。

1887 年 12 月 31 日 23 時 59 分 59 秒の次は 1888 年 1 月 1 日 0 時 18 分 59 秒 になるということですね。

したがって 1888 年 1 月 1 日 0 時 0 分 0 秒 から、0 時 18 分 58 秒までは 1887 年 12 月 31 日と解釈されてしまいます。

	public static void main(String[] args) {
		// 1888 年 1 月 1 日 0 時 0 分 0 秒 ずれる
		LocalDateTime ld = LocalDateTime.of(1888, 1, 1, 0, 0, 0);
		Date date = Date.from(ld.toInstant(ZoneId.systemDefault().getRules().getOffset(ld)));
		System.out.println(date);

		// 1888 年 1 月 1 日 0 時 18 分 58 秒 ずれる
		LocalDateTime ld2 = LocalDateTime.of(1888, 1, 1, 0, 18, 58);
		Date date2 = Date.from(ld2.toInstant(ZoneId.systemDefault().getRules().getOffset(ld2)));
		System.out.println(date2);

		// 1888 年 1 月 1 日 0 時 18 分 59 秒 ずれない
		LocalDateTime ld3 = LocalDateTime.of(1888, 1, 1, 0, 18, 59);
		Date date3 = Date.from(ld3.toInstant(ZoneId.systemDefault().getRules().getOffset(ld3)));
		System.out.println(date3);
	}

結果

Sat Dec 31 23:41:01 JST 1887
Sat Dec 31 23:59:59 JST 1887
Sun Jan 01 00:18:59 JST 1888

怪現象の原因が判明してすっきりしました。

情報をくださった fog_og_frog2 様 本当にありがとうございました。

スッキリわかるJava入門 第2版 (スッキリシリーズ)

スッキリわかるJava入門 第2版 (スッキリシリーズ)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

  • 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/06/23
  • メディア: 単行本(ソフトカバー)
  • 購入: 68人 クリック: 1,802回
  • この商品を含むブログ (138件) を見る
増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門