Joda-Timeの紹介

Joda-Timeの概要

1. 前書き

Joda-Timeは、Java 8がリリースされる前の、最も広く使用されている日時処理ライブラリです。 その目的は、日付と時刻を処理するための直感的なAPIを提供し、Java Date / Time APIに存在していた設計の問題に対処することでした。

The central concepts implemented in this library were introduced in the JDK core with the release of the Java 8 version.新しい日付と時刻のAPIは、java.timeパッケージ(JSR-310)にあります。 これらの機能の概要は、このarticleにあります。

Java 8のリリース後、作成者はプロジェクトがほぼ終了したと見なし、可能であればJava 8APIを使用することをお勧めします。

2. Joda-Timeを使用する理由

Java 8より前の日付/時刻APIには、複数の設計上の問題がありました。

問題の中には、DateクラスとSimpleDateFormatterクラスがスレッドセーフではないという事実があります。 この問題に対処するには、Joda-Time uses immutable classes for handling date and time.

Dateクラスは実際の日付を表すのではなく、ミリ秒の精度で瞬間を指定します。 Dateの年は1900年から始まりますが、ほとんどの日付操作では通常、1970年1月1日から始まるエポック時間が使用されます。

また、Dateの日、月、年のオフセットは直感に反します。 日は0から始まり、月は1から始まります。 それらのいずれかにアクセスするには、Calendarクラスを使用する必要があります。 Joda-Time offers a clean and fluent API for handling dates and time.

Joda-Timeはsupport for eight calendar systemsも提供しますが、Javaは2つだけを提供します。グレゴリオ暦–java.util.GregorianCalendarと日本語–java.util.JapaneseImperialCalendar

 3. セットアップ

Joda-Timeライブラリの機能を含めるには、Maven Centralから次の依存関係を追加する必要があります。


    joda-time
    joda-time
    2.10

 4. ライブラリの概要

Joda-Timeは、org.joda.timeパッケージのクラスを使用してconcept of date and timeをモデル化します。

これらのクラスの中で最も一般的に使用されるのは次のとおりです。

  • LocalDate –時間のない日付を表します

  • LocalTime –タイムゾーンのない時間を表します

  • LocalDateTime –タイムゾーンなしの日付と時刻の両方を表します

  • Instant – 1970-01-01T00:00:00ZのJavaエポックからの正確な時点をミリ秒単位で表します

  • Duration –2つの時点の間の期間をミリ秒単位で表します

  • PeriodDurationに似ていますが、年、月、日など、日付と時刻オブジェクトの個々のコンポーネントへのアクセスを許可します。

  • Interval –2つの瞬間の間の時間間隔を表します

その他の重要な機能はdate parsers and formattersです。 これらは、org.joda.time.formatパッケージに含まれています。

calendar system and time zone固有のクラスは、org.joda.time.chrono and org.joda.time.tzパッケージにあります。

Joda-Timeの主要な機能を使用して日付と時刻を処理するいくつかの例を見てみましょう。

5. 日付と時刻を表す

5.1. 現在の日付と時刻

The current date, without time information,は、 the LocalDate classからnow()メソッドを使用して取得できます。

LocalDate currentDate = LocalDate.now();

日付情報なしで現在の時刻だけが必要な場合は、LocalTimeクラスを使用できます。

LocalTime currentTime = LocalTime.now();

representation of the current date and time without considering the time zone, we can use LocalDateTimeを取得するには:

LocalDateTime currentDateAndTime = LocalDateTime.now();

これで、currentDateAndTimeを使用して、日付と時刻をモデル化する他のタイプのオブジェクトに変換できます。

メソッドtoDateTime()を使用して、DateTimeオブジェクト(タイムゾーンを考慮)を取得できます。 時間が必要ない場合は、メソッドtoLocalDate()を使用してLocalDateに変換できます。時間が必要な場合は、toLocalTime()を使用してLocalTimeオブジェクトを取得できます。

DateTime dateTime = currentDateAndTime.toDateTime();
LocalDate localDate = currentDateAndTime.toLocalDate();
LocalTime localTime = currentDateAndTime.toLocalTime();

指定されたタイムゾーンの日付または時刻を表すのに役立つAll the above methods have an overloaded method which accepts a DateTimeZone object

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はいくつかのコンストラクタを提供します。 次のオブジェクトを指定できます。

  • Instant

  • JavaDateオブジェクト

  • 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、JavaDate、または1970-01-01T00:00:00Zからのミリ秒数を表す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()を使用できますが、ReadableInstantインターフェイスで提供されているJoda-Time APIメソッドを使用することもできます。 (t4)sも実装します:

assertTrue(instantNow.compareTo(oneMinuteAgoInstant) > 0);
assertTrue(instantNow.isAfter(oneMinuteAgoInstant));
assertTrue(oneMinuteAgoInstant.isBefore(instantNow));
assertTrue(oneMinuteAgoInstant.isBeforeNow());
assertFalse(oneMinuteAgoInstant.isEqual(instantNow));

もう1つの便利な機能は、Instant can be converted to a DateTime object or event a 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クラスについて説明したので、DurationPeriod、およびIntervalを使用する方法の例をいくつか見てみましょう。

6.2. DurationPeriod、およびIntervalを使用する

Durationは、2つの時点の間の時間をミリ秒単位で表します。この場合、2つのInstantsになる可能性があります。 We’ll use this when we need to add or subtract a specific amount of time to or from another Instant without considering chronology and time zones

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();

PeriodDurationの主な違いは、Period is defined in terms of its date and time components (years, months, hours, etc.) and doesn’t represent an exact number of millisecondsです。 Periodの日付と時刻の計算を使用する場合will consider the time zone and daylight saving

たとえば、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. 日付と時刻の操作

最も一般的な操作のいくつかは、日付と時刻の加算、減算、変換です。 ライブラリは、クラスLocalDateLocalTimeLocalDateTime、およびDateTimeのそれぞれに特定のメソッドを提供します。 これらのクラスは不変であるため、すべてのメソッド呼び出しがそのタイプの新しいオブジェクトを作成することに注意することが重要です。

今のところLocalDateTimeを取り、その値を変更してみましょう。

LocalDateTime currentLocalDateTime = LocalDateTime.now();

currentLocalDateTimeに日を追加するには、plusDays()メソッドを使用します。

LocalDateTime nextDayDateTime = currentLocalDateTime.plusDays(1);

plus()メソッドを使用して、PeriodまたはDurationcurrentLocalDateTime:に追加することもできます。

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);

もう1つの重要な側面は、日付と時刻のクラスタイプを別のタイプに変換できることです。 これを行うには、ライブラリが提供する特定のメソッドを使用できます。

  • toDateTime()LocalDateTimeDateTimeオブジェクトに変換します

  • toLocalDate()LocalDateTimeLocalDateオブジェクトに変換します

  • toLocalTime()– LocalDateTimeをLocalTimeオブジェクトに変換します

  • toDate()LocalDateTimeをJavaDateオブジェクトに変換します

7. タイムゾーンの使用

Joda-Timeを使用すると、さまざまなタイムゾーンを簡単に操作したり、タイムゾーンを変更したりできます。 タイムゾーンに関するすべての側面を表すために使用されるDateTimeZone抽象クラスがあります。

The default time zone used by Joda-Time is selected from the user.timezone Java system property.ライブラリAPIを使用すると、クラスまたは計算ごとに、使用するタイムゾーンを個別に指定できます。 たとえば、LocalDateTimeオブジェクトを作成できます

アプリケーション全体で特定のタイムゾーンを使用することがわかっている場合は、デフォルトのタイムゾーンを設定できます。

DateTimeZone.setDefault(DateTimeZone.UTC);

これ以降、すべての日付と時刻の操作は、特に指定しない限り、UTCタイムゾーンで表されます。

使用可能なすべてのタイムゾーンを表示するには、メソッドgetAvailableIDs():を使用できます。

DateTimeZone.getAvailableIDs()

特定のタイムゾーンで日付または時刻を表す必要がある場合は、クラスLocalTimeLocalDateLocalDateTimeDateTimeのいずれかを使用して、コンストラクターで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ライブラリになり、最近ではその主要な概念がJava8に導入されました。

作成者はそれを“to be a largely finished project”と見なし、Java8実装を使用するために既存のコードを移行することを推奨していることに注意することが重要です。

記事のソースコードはover on GitHubで入手できます。