mike-neckのブログ

Java or Groovy or Swift or Golang

Java8のDate and Time API - ZonedDateTimeを少しだけさわってみる

こんにちわ、みけです。

前回に引き続き、Java8のDate and Time APIについて書いていきます。

今回はZonedDateTimeについて書きます。


ZonedDateTimeクラス

ZonedDateTimeクラスは日時情報に加えて、時差情報をもつクラスです。

最初、よくわからずLocalDateTimeだけを触っていたのですが、

時差などを扱っているうちに、

どちらかといえば、こちらのクラスのほうが便利だなと感じるようになりました。

(ただし、時差を考慮しない場合はこの限りではない)

では実際に動かしてみます。

@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");
    //複数のクラスでSystem.out.printlnしてたらうまく出力できなかったので、ここで一元的に出力してる
    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;
        }
    }
    /**
     * ZonedDateTimeを動かしてみる
     */
    public static class ZonedDateTimeTest {
        //このクラスの名前
        private static final String CLASS = ZonedDateTimeTest.class.getSimpleName();
        //現在時刻(秒まで) - デフォルトタイムゾーンが使われる
        private static final ZonedDateTime NOW = ZonedDateTime.now().truncatedTo(ChronoUnit.SECONDS);
        //現在時刻(秒まで) - 東京の時刻
        private static final ZonedDateTime NOW_IN_ASIA_TOKYO = ZonedDateTime.now(ASIA_TOKYO).truncatedTo(ChronoUnit.SECONDS);
        //現在時刻(秒まで) - グリニッジの時刻
        private static final ZonedDateTime NOW_IN_GMT = ZonedDateTime.now(GMT).truncatedTo(ChronoUnit.SECONDS);
        //ログ出力用
        private static final Queue<Output> QUEUE = new ConcurrentLinkedQueue<>();
        //テスト名出力用
        @Rule
        public TestName testName = new TestName();

        @Test
        public void zonedDateTimeは日時と時差情報を持つ() {
            QUEUE.offer(new Output(withoutZone.format(NOW), CLASS, testName));
        }

        @Test
        public void zonedDateTimeは日時と時差情報を持つのでもちろんゾーンも出力できる() {
            QUEUE.offer(new Output(withZone.format(NOW), CLASS, testName));
        }

        @Test
        public void ゾーンを指定してzonedDateTimeを取得_指定無しの場合は実行中のマシンのゾーンに合わせる() {
            QUEUE.offer(new Output(withZone.format(NOW_IN_ASIA_TOKYO), CLASS, testName));
            assertThat(withZone.format(NOW).equals(withZone.format(NOW_IN_ASIA_TOKYO)), is(true));
        }

        @Test
        public void ゾーンを指定してzonedDateTimeを取得() {
            QUEUE.offer(new Output(withZone.format(NOW_IN_GMT), CLASS, testName));
        }

        @Test
        public void ゾーンが違うので時刻が違うけど同じ時刻() {
            QUEUE.offer(new Output(withoutZone.format(NOW_IN_ASIA_TOKYO), CLASS, testName));
            QUEUE.offer(new Output(withoutZone.format(NOW_IN_GMT), CLASS, testName));
            assertThat(NOW_IN_GMT.isEqual(NOW_IN_ASIA_TOKYO), is(true));
        }
        //ログを一気に出力
        @AfterClass
        public static void outputMessages() {
            log(QUEUE);
        }
    }
}

出力結果

ZonedDateTimeTest - 2014/09/05 18:14:28 +0900 <- ゾーンを指定してzonedDateTimeを取得_指定無しの場合は実行中のマシンのゾーンに合わせる
ZonedDateTimeTest - 2014/09/05 09:14:28 +0000 <- ゾーンを指定してzonedDateTimeを取得
ZonedDateTimeTest - 2014/09/05 18:14:28 +0900 <- zonedDateTimeは日時と時差情報を持つのでもちろんゾーンも出力できる
ZonedDateTimeTest - 2014/09/05 18:14:28 <- zonedDateTimeは日時と時差情報を持つ
ZonedDateTimeTest - 2014/09/05 18:14:28 <- ゾーンが違うので時刻が違うけど同じ時刻
ZonedDateTimeTest - 2014/09/05 09:14:28 <- ゾーンが違うので時刻が違うけど同じ時刻

最初のテストzonedDateTimeは日時と時差情報を持つZonedDateTime

時刻と時差をもっているというのに、時刻しか出力していないので、

何かありがたさがわからないような結果になっています。


次のテストzonedDateTimeは日時と時差情報を持つのでもちろんゾーンも出力できるは、

結果をゾーン付きで出力しています。

LocalDateTimeクラスではこの書式で例外が発生していたのに対して、

ZonedDateTimeは時差の情報を持つので、このフォーマットで出力できます。


3つ目のテストゾーンを指定してzonedDateTimeを取得_指定無しの場合は実行中のマシンのゾーンに合わせる

では、ZonedDateTime.nowZonedDateTime.now(ASIA_TOKYO)の結果を比べています。

僕のマシーンは東京の設定をしているので、

デフォルトタイムゾーンは東京になっています。

したがって、ZonedDateTime.nowZonedDateTime.now(ASIA_TOKYO)の比較結果は

等しいという事になっています。


4つ目のテストゾーンを指定してzonedDateTimeを取得では、GMTでの時刻を出力しています。

東京の時刻に比べて、9時間遅い時刻が時差(+0:00)で出力されています。


最後のテストゾーンが違うので時刻が違うけど同じ時刻では、

ZonedDateTime.now(ASIA_TOKYO)ZonedDateTime.now(GMT)との比較をしています。

この二つをゾーンなしフォーマットで出力すると、全然違う時刻ですが、

実際に比べてみると等しい時刻であるということがわかります。


以上。

次回は文字列から日付を取得する方法について書きます。