『
Java8.0 ラムダ式とストリームapi』に引き続き、今回はJava8で変更された日付ライブラリと、Java8から導入されたちょっとした変更点についてみていく。
■ 新しい日付ライブラリ(Date-Time API) 概要
旧日付ライブラリ(java.util.Dateなど)の欠点を克服したライブラリ。ちなみに、JavaDocを見る限り旧日付ライブラリはJava8には含まれていない模様。主な改善点は以下の通り。
- スレッド・セーフ化(インスタンス作成時以外に内部変数の値は変更できないようになった)
- 西暦(ISO-8601)だけでなく、和暦(JIS X 0301)など多数の暦に対応。
■ 3つの時間表現 / 和暦
Date-Time APIでは以下の3つの時間表現が存在し、それぞれがパッケージにまとめられている。ZonedDateTimeが日付、時間、タイムゾーン、オフセット情報のすべてをあわせ持つ。
- LocalDateTime…ユーザの実行環境(OS)が管理している時間を表す。解像度はナノ秒。タイムゾーンを考慮しない
- OffsetDateTime…LocalDateTime + オフセット(グリニッジ天文台からの時差)情報
- ZonedDateTime…OffsetDateTime + タイムゾーン情報
また、上記の時間表現に加え、Java8からは和暦クラスも追加された。西暦から和暦への変換方法など、各クラスの動作についてサンプルプログラムを以下に示す。
サンプルコード
package application;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.chrono.JapaneseChronology;
import java.time.chrono.JapaneseDate;
public class TestDateTime {
public static void main(String[] args)
{
// 現在時刻の出力
// LocalDateTime , OffsetDateTime , ZonedDateTimeの保持情報の違いを確認する
System.out.println( LocalDateTime.now() );
System.out.println( OffsetDateTime.now() );
System.out.println( ZonedDateTime.now() );
// 和暦への変換・出力
JapaneseDate jpDate = JapaneseChronology.INSTANCE.date( LocalDateTime.now() );
System.out.println( jpDate );
}
}
実行結果
2015-10-01T17:16:23.442
2015-10-01T17:16:23.442+09:00
2015-10-01T17:16:23.457+09:00[Asia/Tokyo]
Japanese Heisei 27-10-01
■ 文字列⇔日付変換/
文字列から日付クラスへの変換、日付クラスから文字列への変換にはDateTimeFormatterクラスを利用する。この際、文字列を解析するパターンを指定する必要があり、パターンの指定方法は
JavaDoc(クラスDateTimeFormatter)に説明がある。
サンプルコード
package application;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class TestTimeConv {
public static void main(String[] args)
{
// 文字列→日付(フォーマットを指定して生成)
DateTimeFormatter formatterIn = DateTimeFormatter.ofPattern( "yyyy/MM/dd kk:mm:ss" );
LocalDateTime timeIn = LocalDateTime.parse( "1999/02/05 23:11:22" , formatterIn );
// 日付→文字列(フォーマットを指定して出力)
DateTimeFormatter formatterOut = DateTimeFormatter.ofPattern( "yyyy年MM月dd日 kk時mm分ss秒" );
String timeOut = formatterOut.format( timeIn );
System.out.println( timeOut );
}
}
実行結果
1999年02月05日 23時11分22秒
■ 時間計測
上記では日付・時刻情報を持ったクラスを見てきたが、ここでは2点間の時間差を計測する方法を見ていく。時間計測を行う場合にはエポック秒(1970年1月1日0時0分からの経過秒数)をナノ秒単位で保持するInstantクラスと、時間間隔(日数~ナノ秒)を計算するChronoUnitクラスの利用が便利である。
サンプルコード
package application;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class TestInstant {
public static void main(String[] args)
{
// タイムスタンプの取得
Instant before = Instant.now();
// タイムスタンプを出力
Long milliSec = before.getEpochSecond();
int nanoSec = before.getNano();
System.out.println( "1970年01月01日 0:00からの経過ナノ秒:" + ( milliSec*1000000000L + nanoSec ) );
// スリープ
try {
Thread.sleep( 3000 );
} catch (InterruptedException e) {
e.printStackTrace();
}
// 時間計測
Instant after = Instant.now();
Long gap = ChronoUnit.NANOS.between( before , after );
System.out.println( "時間差:" + gap + "(nano秒)" );
}
}
実行結果
1970年01月01日 0:00からの経過ナノ秒:1443694726623000000
時間差:3014000000(nano秒)
実行結果を見ると、実際に計測できたのはミリ秒の精度となっている。これはプログラムを実行した環境(PC)の時間計測が可能な精度がミリ秒であるためで、高性能な実行環境ではナノ秒の精度の値が返ってくる(ハズ)。
■ アジャスターとクエリ
時間に関するクラスとして、Java 8 からアジャスターとクエリが追加された。アジャスター(TemporalAdjusterクラス)は『ある年の最初の月曜日』など、時間オブジェクトの日付調整を行うクラスである。また、クエリ(TemporalQueryクラス)は時間オブジェクトの内容を照会するクラスである。
書いてても何いってるのか分からないため、以下にアジャスターとクエリを用いたサンプルを示す。
サンプルコード
package application;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
public class TestTimeAdjuster {
public static void main(String[] args)
{
// 今月の月初めの月曜日を求める
LocalDateTime date = LocalDateTime.now();
TemporalAdjuster adjuster = TemporalAdjusters.firstInMonth( DayOfWeek.MONDAY );
System.out.println( "今日は" + date + "です。" );
System.out.println( "月初めの月曜日は" + date.with( adjuster ) + "です。" );
// 時間オブジェクトの精度を求める
TemporalQuery<TemporalUnit> query = TemporalQueries.precision();
System.out.println( "LocalDateTimeの精度は" + date.query( query ) );
}
}
実行結果
今日は2015-10-01T19:35:09.933です。
月初めの月曜日は2015-10-05T19:35:09.933です。
LocalDateTimeの精度はNanos
■ 参照
- The Java™ Tutorials(Trail: Date Time: Table of Contents) → 新しい日付ライブラリの説明(英文)