こんにちわ、みけです。
わけありで、LocalDateTime
とかZonedDateTime
を
触っててわからんところいっぱいあったので、
メモってみました。
Java8のData and Time Apiはこれだけではないけど、
はじめて触る人がハマるだろう箇所にとことんはまっています。
LocalDateTime
クラス
LocalDateTime
クラスは日時情報だけを持つクラスです。
文字列に出力するときDateTimeFormatter
を用いますが、
タイムゾーンを表すフォーマッターが入ってると、
実行時例外が発生します。
package sample; import org.junit.AfterClass; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.rules.TestName; import org.junit.runner.RunWith; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.UnsupportedTemporalTypeException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; @RunWith(Enclosed.class) public class DateTimeTest { private static final Object LOCK = new Object(); private static final DateTimeFormatter withoutZone = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); private static final DateTimeFormatter withZone = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss Z"); private static final ZoneId ASIA_TOKYO = ZoneId.of("Asia/Tokyo"); private static final ZoneId GMT = ZoneId.of("GMT"); private synchronized static void log(Queue<Output> outputs) { while (outputs.size() > 0) { synchronized (LOCK) { System.out.println(outputs.poll()); } } } private static class Output { final String message; final String className; final String methodName; private Output(String message, String className, TestName testName) { this.message = message; this.className = className; this.methodName = testName.getMethodName(); } @Override public String toString() { return className + " - " + message + " <- " + methodName; } } public static class LocalDateTimeTest { private static final String CLASS = LocalDateTimeTest.class.getSimpleName(); private static final LocalDateTime NOW = LocalDateTime.now(); private static final LocalDateTime NOW_AT_ASIA_TOKYO = LocalDateTime.now(ASIA_TOKYO); private static final LocalDateTime NOW_AT_GMT = LocalDateTime.now(GMT); private static final Queue<Output> QUEUE = new ConcurrentLinkedQueue<>(); @Rule public TestName testName = new TestName(); @Test public void localDateTimeは日時の情報だけを持つ() { QUEUE.offer(new Output(withoutZone.format(NOW), CLASS, testName)); } @Test(expected = UnsupportedTemporalTypeException.class) public void localDateTimeは日時の情報だけを持っているのでゾーンを出力しようとすると例外() { withZone.format(NOW); } @Test public void ゾーン指定して取得したLocalDateTime() { QUEUE.offer(new Output(withoutZone.format(NOW_AT_ASIA_TOKYO), CLASS, testName)); } @Test(expected = UnsupportedTemporalTypeException.class) public void ゾーン指定して取得したLocalDateTimeでもゾーンは持たない() { withZone.format(NOW_AT_ASIA_TOKYO); } @Test public void ゾーン指定して取得したLocalDateTimeは時間が異なる() { QUEUE.offer(new Output(withoutZone.format(NOW_AT_ASIA_TOKYO), CLASS, testName)); QUEUE.offer(new Output(withoutZone.format(NOW_AT_GMT), CLASS, testName)); assertThat(NOW_AT_GMT.isBefore(NOW_AT_ASIA_TOKYO), is(true)); } @AfterClass public static void outputMessages() { log(QUEUE); } } }
出力結果
LocalDateTimeTest - 2014/09/05 18:14:28 <- localDateTimeは日時の情報だけを持つ LocalDateTimeTest - 2014/09/05 18:14:28 <- ゾーン指定して取得したLocalDateTimeは時間が異なる LocalDateTimeTest - 2014/09/05 09:14:28 <- ゾーン指定して取得したLocalDateTimeは時間が異なる LocalDateTimeTest - 2014/09/05 18:14:28 <- ゾーン指定して取得したLocalDateTime
本質的でないコードも多くありますが…
最初のメソッドlocalDateTimeは日時の情報だけを持つ
は、
単純にLocalDateTime.now()
の結果を
ゾーン情報なしのフォーマットで出力します。
2つ目のメソッドlocalDateTimeは日時の情報だけを持っているのでゾーンを出力しようとすると例外
は、
LocalDateTime.now()
の結果をゾーン情報ありのフォーマットで出力しようと
しますが、ゾーン情報をLocalDateTime
は持たないので、
UnsupportedTemporalTypeException
を出して終了します。
また、4つ目のメソッドではLocalDateTime.now
に、
ZoneId
を渡してLocalDateTime
を取得したものを、
ゾーン情報ありのフォーマットで出力しようとしていますが、
これもUnsupportedTemporalTypeException
を出して終了します。
また、5つ目のメソッドではLocalDateTime.now
に
異なるZoneId
を渡した日時を比較しています。
標準出力の結果からもわかると思いますが、
GMT
で取得した日時はAsia/Tokyo
で取得した日時よりも、
9時間前の時間になるので、
gmt.isBefore(asiaTokyo)
の結果はtrue
になります。
その他は次回以降。