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]から入手できます。