ちょっとエポックタイムを使った比較を作った時にハマったので備忘録としてまとめ。
とりあえず説明よりも以下のコードと実行結果を見てほしい。
普通にjava.util.Dateを引数0で初期化
EpochTest1.java
import java.text.SimpleDateFormat;
import java.util.Date;
public class EpochTest1 {
public static void main(String[] args) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 0指定で初期化
Date epoch = new Date(0);
System.out.println(fmt.format(epoch));
}
}
実行結果
1970-01-01 09:00:00
あれ?9時間ずれてる・・・
9時間ってことはタイムゾーンの関係なんだろう。
めんどくさいけどCalendar使うか・・
java.util.Calendarを使ってみる
EpochTest2.java
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class EpochTest2 {
public static void main(String[] args) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Calendarをタイムゾーン指定して作成
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
// 0ミリ秒を設定
cal.setTimeInMillis(0);
Date epoch = cal.getTime();
System.out.println(fmt.format(epoch));
}
}
実行結果
1970-01-01 09:00:00
あり?Calendar使ってもずれてる・・・
DateFormatのタイムゾーン設定
EpochTest3.java
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class EpochTest3 {
public static void main(String[] args) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Dateformatのタイムゾーン設定
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
// 0指定で初期化
Date epoch = new Date(0);
System.out.println(fmt.format(epoch));
}
}
実行結果
1970-01-01 00:00:00
というわけでDateFormatのタイムゾーンの設定の問題でした。
内部的にはDate epoch = new Date(0);
とかでちゃんとエポック秒になっている。
でも文字列として変換する際にUTCエポック秒はJSTでは+09:00なので
SimpleDateFormatとかで変換すると1970-01-01 09:00:00
になってしまう。
ただこれがちょっと問題で、テンプレートエンジンとかで
dateformatのタイムゾーンとかがいじりにくい場合、
日付の生成にミリ秒を使うと意図せずずれることがある。
なのでデフォルトロケールの"1970-01-01 00:00:00"を作成する方法も知っとくとハマらない。
文字列から初期化
EpochTest4.java
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class EpochTest4 {
public static void main(String[] args) throws ParseException {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// DateFormat使って作成すればOK(当たり前
Date epoch = fmt.parse("1970-01-01 00:00:00");
System.out.println(fmt.format(epoch));
// java.sql.TimestampはvalueOfを使うとDateFormatとか作らなくても狙った時間の初期化ができる。
// ただしフォーマットはyyyy-mm-dd hh:mm:ss[.fffffffff]固定。
System.out.println(fmt.format(Timestamp.valueOf("1970-01-01 00:00:00")));
}
}
実行結果
1970-01-01 00:00:00
1970-01-01 00:00:00
結局表示に使うのであれば文字列としての日付型をparseする方法がベターなのかな?