ImmutableでスレッドセーフになったJavaの新しい日時APIの基礎知識:ここが大変だよJava 8 Date-Time API(1)(4/5 ページ)
Date-Time APIの概要や、Java 8より前の旧日時APIから何が改善されたのかに加え、新しく追加されたさまざまなクラスについて解説します。
タイムラインを表すクラス(Instant)
今まで見てきたLocalDateTimeなどのクラスは、私たちが一般的に認識する年や月などの単位から扱っていましたが、マシン時刻として扱われるエポック(1970年1月1日の0時0分0秒)からの経過時間(タイムライン)による時間を表すInstantというクラスがDate-Time APIで用意されています。Instantではエポックより前の経過時間をマイナスの値で持ち、エポックより後の経過時間をプラスの値で持っています。
またInstantから各DateTimeクラスとOffsetTimeを生成するためのofInstantメソッドが用意されています。このofInstantメソッドは引数にInstantとZoneIdを受け取り、Instantの持つタイムラインからタイムゾーンの情報を反映した結果を返します。
Instant insatnt = Instant.now(); LocalDateTime localDateTime = LocalDateTime.ofInstant(insatnt, ZoneId.systemDefault()); System.out.println("localDateTime=" + localDateTime); ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(insatnt, ZoneId.systemDefault()); System.out.println("zonedDateTime=" + zonedDateTime); OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(insatnt, ZoneId.systemDefault()); System.out.println("offsetDateTime=" + offsetDateTime);
localDateTime=2014-09-01T15:28:54.296 zonedDateTime=2014-09-01T15:28:54.296+09:00[Asia/Tokyo] offsetDateTime=2014-09-01T15:28:54.296+09:00
そして逆に各DateTimeからInstantを生成するためのtoIsnatntメソッドも用意されています。
LocalDateTime localDateTime = LocalDateTime.of(2010, Month.JANUARY, 1, 12, 10, 10, 10); Instant instant = localDateTime.toInstant(ZoneOffset.of("+6")); System.out.println("instant=" + instant); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("America/New_York")); instant = zonedDateTime.toInstant(); System.out.println("instant=" + instant); OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, ZoneOffset.of("+04:00")); instant = offsetDateTime.toInstant(); System.out.println("instant=" + instant);
instant=2010-01-01T06:10:10.000000010Z instant=2010-01-01T17:10:10.000000010Z instant=2010-01-01T08:10:10.000000010Z
期間を表すクラス
Date-Time APIには今まで見てきた対象の時間的な時点を表すクラスの他に、いつからいつまでのような時間的な長さを、期間として表すクラスも用意されています。次の2つです。
- Duration:秒とナノ秒を基に期間を表すクラス
- Period:年月日を基に期間を表すクラス
時間ベースでの期間を表すクラス(Duration)
Durationクラスは秒とナノ秒を基に期間を表すクラスです。要素として秒と秒未満の値としてのナノ秒を持っています。例えばThreadを1.5秒(1500ミリ秒)ほど停止した際の時間差を値として持つDurationのインスタンスを生成した場合、このインスタンスが持つ秒の要素は「1」で、ナノ秒の要素は1秒未満の値をナノ秒で表したものを持つことになります。
Instant start = Instant.now(); Thread.sleep(1500); // 1.5秒ほどスレッドを停止 Instant end = Instant.now(); Duration duration = Duration.between(start, end); System.out.println("duration=" + duration); System.out.println("duration.getSeconds()=" + duration.getSeconds()); System.out.println("duration.getNano()=" + duration.getNano());
duration=PT1.513S duration.getSeconds()=1 duration.getNano()=513000000
また、マイナスの値を持つことも可能で、開始時間が終了時間より新しい場合の期間を表せます。
このDurationクラスは単純な時間での期間を表すクラスであり、サマータイム制などの影響は無視されます。例えば、2014年のロサンゼルスでのサマータイムは3月9日の2時から始まります。そのため3月9日の2時は3月9日の3時となり、3月9日の1時から3月9日の3時までのDurationを取得した場合、そのDurationの持っている値は1時間となります。
ZoneId zoneId = ZoneId.of("America/Los_Angeles"); ZonedDateTime start = ZonedDateTime.of(LocalDateTime.of(2014, Month.MARCH, 9, 1, 0, 0, 0), zoneId); ZonedDateTime end = ZonedDateTime.of(LocalDateTime.of(2014, Month.MARCH, 9, 2, 0, 0, 0), zoneId); Duration duration = Duration.between(start, end); System.out.println("start=" + start); System.out.println("end=" + end); System.out.println("duration=" + duration); System.out.println("duration.getSeconds()=" + duration.getSeconds()); System.out.println("duration.getNano()=" + duration.getNano());
start=2014-03-09T01:00-08:00[America/Los_Angeles] end=2014-03-09T03:00-07:00[America/Los_Angeles] duration=PT1H duration.getSeconds()=3600 duration.getNano()=0
※Durationクラスは「to」から始まるメソッドで日、時、分、ミリ秒、ナノ秒で換算した値を取得することが可能です。また、その際に発生した端数は切り捨てられます。
※秒はgetSecondsメソッドで取得可能なため「to」で始まるメソッドはありません。
LocalDateTime start = LocalDateTime.of(2014, Month.JANUARY, 1, 0, 0, 0, 0); LocalDateTime end = LocalDateTime.of(2014, Month.JANUARY, 2, 12, 30, 30, 300); Duration duration = Duration.between(start, end); System.out.println("duration.toNanos()=" + duration.toNanos()); System.out.println("duration.toMillis()=" + duration.toMillis()); System.out.println("duration.getSeconds()=" + duration.getSeconds()); System.out.println("duration.toMinutes()=" + duration.toMinutes()); System.out.println("duration.toHours()=" + duration.toHours()); System.out.println("duration.toDays()=" + duration.toDays());
duration.toNanos()=131430000000300 duration.toMillis()=131430000 duration.getSeconds()=131430 duration.toMinutes()=2190 duration.toHours()=36 duration.toDays()=1
年月日ベースでの期間を表すクラス(Period)
Periodクラスは年と月と日を基に期間を表すクラスです。要素として年と月と日を持っています。例えば2013年1月1日から2014年1月1日までの期間を表したPeriodのインスタンスを生成した場合、このインスタンスが持つ年の要素は「1」、月の要素は「0」、日の要素は「0」を持つことになります。また、Durationクラスと同様にマイナスの値を持つことも可能です。
LocalDate start = LocalDate.of(2013, Month.JANUARY, 1); LocalDate end = LocalDate.of(2014, Month.JANUARY, 1); Period period = Period.between(start, end); System.out.println("period=" + period); System.out.println("period.getYears()=" + period.getYears()); System.out.println("period.getMonths()=" + period.getMonths()); System.out.println("period.getDays()=" + period.getDays());
period=P1Y period.getYears()=1 period.getMonths()=0 period.getDays()=0
ただし、Durationクラスと違い、Periodクラスは「to」から始まるメソッドは月数を取得するtoTotalMonthメソッドしかありません。getYearsメソッドで年数は取得できるのですが、日数に関してはChronoUnit.DAYSのbetweenメソッドを使うなどして換算しないといけません。
LocalDate start = LocalDate.of(2013, Month.JANUARY, 1); LocalDate end = LocalDate.of(2014, Month.JANUARY, 1); Period period = Period.between(start, end); System.out.println("period.getYears()=" + period.getYears()); System.out.println("period.toTotalMonths()=" + period.toTotalMonths()); long days = ChronoUnit.DAYS.between(start, end); System.out.println("日数=" + days);
period.getYears()=1 period.toTotalMonths()=12 日数=365
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 初心者のためのJavaラムダ式入門とJDKのインストール、IDEの環境構築
本連載では、今までJavaの経験はあっても「ラムダ式は、まだ知らない」という人を対象にラムダ式について解説していきます。初回は、ラムダ式の概要と利点、必要性、JDK 8のセットアップ、NetBeans、IntelliJ IDEA、Eclipseの環境構築について。 - ラムダ式、JAR脱獄、JavaScript/Node.jsに接近するJDK 8、そして9へ
- Java 8&Java EE 7に対応した「Spring Framework 4.0」正式版リリース
米Pivotalは2013年12月12日、オープンソースのJavaアプリケーションフレームワーク「Spring Framework 4.0」の正式版をリリースした。 - JDK 8、TLS 1.2がデフォルトに
Javaの通信暗号化もTSL 1.2に。基本的に後方互換性は維持するが、一部影響がある場合もあるという。