Joda-Timeの紹介
1.はじめに
Joda-Timeは、Java 8がリリースされる前の、最も広く使用されている日時処理ライブラリです。その目的は、日時を処理するための直感的なAPIを提供し、さらにJava Date/Time APIに存在した設計問題に対処することです。
-
このライブラリに実装されている中心的な概念は、Java 8バージョンのリリースとともにJDKコアで導入されました** 新しい日時APIは、
java.time
パッケージ(https://jcp.org/ja/jsr)にあります。/detail?id = 310[JSR-310]。これらの機能の概要はこのリンクにあります:/java-8-date-time-intro[article]。
Java 8のリリース後、作者はプロジェクトがほぼ完成したと考えており、可能ならばJava 8 APIを使用することを勧めます
2.なぜJoda-Timeを使うのですか?
Java 8より前の日付/時刻APIは、複数の設計上の問題を抱えていました。
問題の中には、
Date
クラスと
SimpleDateFormatter
クラスがスレッドセーフではないという事実があります。この問題に対処するために、
Joda-Timeは日付と時刻を処理するために不変クラスを使用しています。
Date
クラスは実際の日付を表すものではありませんが、代わりにミリ秒の精度で時刻を指定します。
Date
の年は1900年から始まりますが、ほとんどの日付操作は通常1970年1月1日から始まるエポック時間を使用します。
また、
Date
の日、月、年のオフセットは直感に反するものです。
日は0から始まり、月は1から始まります。それらにアクセスするには、
Calendar
クラスを使用する必要があります。 Joda-Timeは日付と時刻を処理するためのクリーンで流暢なAPIを提供します。
Joda-Timeは
8つのカレンダーシステム
のサポートも提供しますが、Javaは2:Gregorian –
java.util.GregorianCalendar
とJapanese –
java.util.JapaneseImperialCalendar
のみを提供します。
3.セットアップ
Joda-Timeライブラリの機能を含めるには、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22joda-time%22%20AND%から以下の依存関係を追加する必要があります。 20a%3A%22時間 – %22[Maven Central]:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10</version>
</dependency>
4.図書館の概要
Joda-Timeは
org.joda.time
パッケージのクラスを使って
日付と時間の概念
をモデル化します。
これらのクラスの中で最も一般的に使われているものは:
-
LocalDate
– 時間のない日付を表します -
LocalTime
– タイムゾーンなしの時間を表します -
LocalDateTime
– 時間なしの日付と時刻の両方を表します
ゾーン
**
Instant
– 開始からのミリ秒単位の正確な時点を表します。
1970-01-01T00のJavaエポック:00:00Z
**
Duration
– 2点間の期間をミリ秒単位で表します
やがて
**
Period
–
Duration
に似ていますが、個人へのアクセスを許可します
年、月、日など、日付および時刻オブジェクトの構成要素
-
Interval
– 2つの時点の間の時間間隔を表します
その他の重要な機能は
日付パーサとフォーマッタ
です。これらは
org.joda.time.format
パッケージにあります。
-
カレンダーシステムとタイムゾーン
固有のクラスは
org.joda.time.chrono
と
org.joda.time.tz
** パッケージにあります。
Joda-Timeの主な機能を使って日付と時刻を処理する例を見てみましょう。
5.日付と時刻を表す
5.1. 現在の日時
-
時間情報なしの現在の日付
は、
**
LocalDate
クラスの__now()メソッドを使用して取得できます。
LocalDate currentDate = LocalDate.now();
日付情報なしで現在時刻だけが必要な場合は、
LocalTime
クラスを使用できます。
LocalTime currentTime = LocalTime.now();
タイムゾーンを考慮せずに現在の日付と時刻の
表現を取得するには、
LocalDateTime
を使用できます。
LocalDateTime currentDateAndTime = LocalDateTime.now();
これで、
currentDateAndTime
を使用して、日付と時刻をモデリングする他の種類のオブジェクトに変換できます。
メソッド
toDateTime()
を使用して
DateTime
オブジェクト(タイムゾーンを考慮に入れる)を取得できます。時間が不要な場合は、メソッド
toLocalDate()
を使用して
LocalDate
に変換できます。時間が必要な場合は
toLocalTime()
を使用して
LocalTime
オブジェクトを取得できます。
DateTime dateTime = currentDateAndTime.toDateTime();
LocalDate localDate = currentDateAndTime.toLocalDate();
LocalTime localTime = currentDateAndTime.toLocalTime();
-
上記のすべてのメソッドは
DateTimeZone
オブジェクトを受け取るオーバーロードされたメソッドを持ちます。
LocalDate currentDate = LocalDate.now(DateTimeZone.forID("America/Chicago"));
また、Joda-TimeはJava Date and Time APIとの優れた統合を提供します。コンストラクタは
java.util.Date
オブジェクトを受け入れます。また、
toDate()
メソッドを使用して
java.util.Date
オブジェクトを返すこともできます。
LocalDateTime currentDateTimeFromJavaDate = new LocalDateTime(new Date());
Date currentJavaDate = currentDateTimeFromJavaDate.toDate();
5.2. カスタムの日付と時刻
カスタムの日付と時刻を表すために、Joda-Timeはいくつかのコンストラクタを提供しています。以下のオブジェクトを指定することができます。
-
一瞬__
-
Javaの
Date
オブジェクト -
ISOフォーマットを使用した日付と時刻の
String
表現 -
日付と時刻の部分:年、月、日、時、分、秒、
ミリ秒
Date oneMinuteAgoDate = new Date(System.currentTimeMillis() - (60 ** 1000));
Instant oneMinutesAgoInstant = new Instant(oneMinuteAgoDate);
DateTime customDateTimeFromInstant = new DateTime(oneMinutesAgoInstant);
DateTime customDateTimeFromJavaDate = new DateTime(oneMinuteAgoDate);
DateTime customDateTimeFromString = new DateTime("2018-05-05T10:11:12.123");
DateTime customDateTimeFromParts = new DateTime(2018, 5, 5, 10, 11, 12, 123);
カスタムの日付と時刻を定義するもう1つの方法は、ISO形式の日付と時刻の指定された
String
表現を解析することです。
DateTime parsedDateTime = DateTime.parse("2018-05-05T10:11:12.123");
カスタム
DateTimeFormatter
を定義して、日付と時刻のカスタム表現を解析することもできます。
DateTimeFormatter dateTimeFormatter
= DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss");
DateTime parsedDateTimeUsingFormatter
= DateTime.parse("05/05/2018 10:11:12", dateTimeFormatter);
6.日付と時刻を操作する
6.1.
Instant
を使う
Instant
は、1970-01-01T00:00:00Zから特定の時点までのミリ秒数を表します。たとえば、現在の時刻は、デフォルトのコンストラクタまたはメソッド
now()
を使用して取得できます。
Instant instant = new Instant();
Instant.now();
カスタムの瞬間に
Instant
を作成するには、コンストラクタの1つを使うか、
ofEpochMilli()
メソッドと
ofEpochSecond()
メソッドを使います。
Instant instantFromEpochMilli
= Instant.ofEpochMilli(milliesFromEpochTime);
Instant instantFromEpocSeconds
= Instant.ofEpochSecond(secondsFromEpochTime);
コンストラクタは、ISO形式の日時を表す
String
、1970-01-01T00:00:00Zからのミリ秒数を表すJavaの
Date
または
long
の値を受け入れます。
Instant instantFromString
= new Instant("2018-05-05T10:11:12");
Instant instantFromDate
= new Instant(oneMinuteAgoDate);
Instant instantFromTimestamp
= new Instant(System.currentTimeMillis() - (60 ** 1000));
日付と時刻が
String
として表されている場合は、希望の形式を使用して
String
を解析することができます。
Instant parsedInstant
= Instant.parse("05/05/2018 10:11:12", dateTimeFormatter);
Instant
が何を表し、どのようにしてそれを作成できるかがわかったので、それをどのように使用できるかを見てみましょう。
Instant
オブジェクトと比較するには、
Comparable
インターフェースを実装しているので
compareTo()
を使用できますが、
Instant
が実装している
ReadableInstant
インターフェースで提供されるJoda-Time APIメソッドも使用できます。
assertTrue(instantNow.compareTo(oneMinuteAgoInstant) > 0);
assertTrue(instantNow.isAfter(oneMinuteAgoInstant));
assertTrue(oneMinuteAgoInstant.isBefore(instantNow));
assertTrue(oneMinuteAgoInstant.isBeforeNow());
assertFalse(oneMinuteAgoInstant.isEqual(instantNow));
もう1つの便利な機能は、
Instant
を
DateTime
オブジェクトに変換したり、Javaの
Date
イベントにすることができることです。
DateTime dateTimeFromInstant = instant.toDateTime();
Date javaDateFromInstant = instant.toDate();
年や時間など、日付と時刻の一部にアクセスする必要があるときは、
get()
メソッドを使用して
DateTimeField
を指定できます。
int year = instant.get(DateTimeFieldType.year());
int month = instant.get(DateTimeFieldType.monthOfYear());
int day = instant.get(DateTimeFieldType.dayOfMonth());
int hour = instant.get(DateTimeFieldType.hourOfDay());
Instant
クラスをカバーしたので、
Duration
、
Period
、および
Interval
の使用方法の例をいくつか見てみましょう。
6.2.
Duration
、
Period
、および
Interval
を使用する
Duration
は、2つの時点間のミリ秒単位の時間を表します。この場合は、2つの
Instants
になります。
時系列やタイムゾーンを考慮せずに、他の
Instant
との間で特定の時間を加算または減算する必要がある場合は、これを使用します
。
long currentTimestamp = System.currentTimeMillis();
long oneHourAgo = currentTimestamp - 24** 60** 1000;
Duration duration = new Duration(oneHourAgo, currentTimestamp);
Instant.now().plus(duration);
また、期間が表す日数、時間数、分数、秒数、またはミリ秒数を決定できます。
long durationInDays = duration.getStandardDays();
long durationInHours = duration.getStandardHours();
long durationInMinutes = duration.getStandardMinutes();
long durationInSeconds = duration.getStandardSeconds();
long durationInMilli = duration.getMillis();
Period
と
Duration
の主な違いは、
Period
は日付と時刻の構成要素(年、月、時など)で定義されており、正確なミリ秒数を表すものではないことです
。
日付と時刻の計算
Period__を使用するときは
タイムゾーンと夏時間
を考慮します。
たとえば、2月1日に1月の
Period
を追加すると、3月1日の日付表現になります。
Period
を使うことで、ライブラリはうるう年を考慮に入れます。
Duration
を使用する場合、結果は正しくありません。これは、
Duration
が、年代順やタイムゾーンを考慮に入れていない固定の時間を表すためです。
Period period = new Period().withMonths(1);
LocalDateTime datePlusPeriod = localDateTime.plus(period);
Interval
は、その名のとおり、2つの
Instant
オブジェクトで表される2つの固定時点間の日付と時間の間隔を表します。
Interval interval = new Interval(oneMinuteAgoInstant, instantNow);
このクラスは、2つの区間が重なっているかどうかをチェックしたり、それらの間のギャップを計算する必要がある場合に役立ちます。
overlap()
メソッドは、オーバーラップしていない場合、オーバーラップしている
Interval
または
null
を返します。
Instant startInterval1 = new Instant("2018-05-05T09:00:00.000");
Instant endInterval1 = new Instant("2018-05-05T11:00:00.000");
Interval interval1 = new Interval(startInterval1, endInterval1);
Instant startInterval2 = new Instant("2018-05-05T10:00:00.000");
Instant endInterval2 = new Instant("2018-05-05T11:00:00.000");
Interval interval2 = new Interval(startInterval2, endInterval2);
Interval overlappingInterval = interval1.overlap(interval2);
区間の差は
gap()
メソッドを使って計算することができ、区間の終わりが別の区間の始まりと等しいかどうか知りたいときは
abuts()
メソッドを使うことができます。
assertTrue(interval1.abuts(new Interval(
new Instant("2018-05-05T11:00:00.000"),
new Instant("2018-05-05T13:00:00.000"))));
6.3. 日付と時刻の操作
最も一般的な操作のいくつかは、日付と時刻の加算、減算、変換です。ライブラリは、各クラス
LocalDate
、
LocalTime
、
LocalDateTime
、および
DateTime
に固有のメソッドを提供します。すべてのメソッド呼び出しがその型の新しいオブジェクトを作成するように、これらのクラスは不変であることに注意することが重要です。
今のところ
LocalDateTime
を使って値を変更してみましょう。
LocalDateTime currentLocalDateTime = LocalDateTime.now();
currentLocalDateTime
に日を追加するには、
plusDays()
メソッドを使用します。
LocalDateTime nextDayDateTime = currentLocalDateTime.plusDays(1);
plus()メソッドを使用して、
currentLocalDateTimeに
Period
または
Duration
を追加することもできます。
Period oneMonth = new Period().withMonths(1);
LocalDateTime nextMonthDateTime = currentLocalDateTime.plus(oneMonth);
これらのメソッドは、他の日付と時刻のコンポーネントでも同様です。たとえば、年を追加するための
plusYears()
、さらに秒を追加するためのplusSeconds()などです。
currentLocalDateTime
から1日を引くには、
minusDays()
メソッドを使います。
LocalDateTime previousDayLocalDateTime
= currentLocalDateTime.minusDays(1);
その上、日付と時刻で計算することで、日付や時刻の個々の部分を設定することもできます。たとえば、時を10に設定することは
withHourOfDay()
メソッドを使用して達成することができます。接頭辞
“ with”
で始まる他のメソッドを使用して、その日付または時刻の構成要素を設定できます。
LocalDateTime currentDateAtHour10 = currentLocalDateTime
.withHourOfDay(0)
.withMinuteOfHour(0)
.withSecondOfMinute(0)
.withMillisOfSecond(0);
もう一つの重要な側面は、日付と時刻のクラス型から別の型に変換できることです。これを行うには、ライブラリが提供する特定のメソッドを使用します。
-
toDateTime()
–
LocalDateTime
を
DateTime
オブジェクトに変換します -
toLocalDate()
–
LocalDateTime
を
LocalDate
オブジェクトに変換します -
toLocalTime() – LocalDateTimeをLocalTimeオブジェクトに変換する
-
toDate()
–
LocalDateTime
をJavaの
Date
オブジェクトに変換します。
7.タイムゾーンを使った作業
Joda-Timeを使えば、さまざまなタイムゾーンで作業したり変更したりできます。タイムゾーンに関するすべての側面を表すために使用される
DateTimeZone
抽象クラスがあります。
-
Joda-Timeによって使用されるデフォルトのタイムゾーンは
user.timezone
Javaシステムプロパティから選択されます** ライブラリAPIは各クラスまたは計算のために使用されるべきタイムゾーンを個別に指定させます。
たとえば、LocalDateTimeオブジェクトを作成できます。
アプリケーション全体で特定のタイムゾーンを使用することがわかったら、デフォルトのタイムゾーンを設定できます。
DateTimeZone.setDefault(DateTimeZone.UTC);
特に指定されていない限り、今から1つすべての日時操作がUTCタイムゾーンで表されます。
利用可能なすべてのタイムゾーンを見るには、__getAvailableIDs()メソッドを使います。
DateTimeZone.getAvailableIDs()
特定のタイムゾーンで日付または時刻を表す必要がある場合は、
LocalTime
、
LocalDate
、
LocalDateTime
、
DateTime
のいずれかのクラスを使用し、コンストラクタで
DateTimeZone
オブジェクトを指定できます。
DateTime dateTimeInChicago
= new DateTime(DateTimeZone.forID("America/Chicago"));
DateTime dateTimeInBucharest
= new DateTime(DateTimeZone.forID("Europe/Bucharest"));
LocalDateTime localDateTimeInChicago
= new LocalDateTime(DateTimeZone.forID("America/Chicago"));
また、これらのクラス間で変換するときに、希望のタイムゾーンを指定できます。メソッド
toDateTime()
は
DateTimeZone
オブジェクトを受け入れ、
toDate()
はjava.util.TimeZoneオブジェクトを受け入れます。
DateTime convertedDateTime
= localDateTimeInChicago.toDateTime(DateTimeZone.forID("Europe/Bucharest"));
Date convertedDate
= localDateTimeInChicago.toDate(TimeZone.getTimeZone("Europe/Bucharest"));
8.まとめ
Joda-Timeは、日付と時刻の操作に関するJDKの問題を解決するという主な目的から始まった素晴らしいライブラリです。それはまもなく日付と時刻を扱うための
de facto
ライブラリとなり、最近ではそれからの主要な概念がJava 8で導入されました。
-
作者はこれを「ほぼ完成したプロジェクト」と見なし、既存のコードを移行してJava 8実装を使用することを推奨することに注意することが重要です。
この記事のソースコードはhttps://github.com/eugenp/tutorials/tree/master/libraries[over GitHub]から入手できます。