連載
» 2014年12月17日 18時00分 公開

ImmutableでスレッドセーフになったJavaの新しい日時APIの基礎知識ここが大変だよJava 8 Date-Time API(1)(4/5 ページ)

[長谷川智之,株式会社ビーブレイクシステムズ]

タイムラインを表すクラス(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
実行結果(3,600秒 = 1時間 × 60分 × 60秒)

※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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。