パッケージ java.time.temporal のおさらいメモ

# 概要

パッケージ java.time.temporalは、Date and Time APIのパッケージjava.timeのサブパッケージで、時間的オブジェクト(temporal object)を操作する基本的なインターフェースや列挙型が定義されています。
この記事は、これらのインターフェースの使い方をおさらいしたときの記録になります。

**環境**

* Windows 10 Professional
* Oracle JDK 1.8.0_162
* Oracle JDK 10.0.1

**参考**

* [パッケージ java.time.temporal - JDK 1.8] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/package-summary.html)
* [パッケージ java.time - JDK 1.8] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/package-summary.html)
* [Oracle JDK 9ドキュメント] (https://docs.oracle.com/javase/jp/9/index.html)
* [Oracle JDK 10ドキュメント] (https://docs.oracle.com/javase/jp/10/index.html)


# [インタフェース Temporal] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/Temporal.html)

> 時間的オブジェクト(日付、時間、オフセット、またはそれらのなんらかの組合せなど)への読取り/書込みアクセスを定義するフレームワークレベルのインタフェースです。

時間的オブジェクト(temporal object)の実装クラスには、LocalDate, LocalDateTime, LocalTime, Year, YearMonthなどがあります。

> **注意**
> このインタフェースはフレームワークレベルのインタフェースであり、アプリケーション・コードで広範囲にわたって使用しないようにしてください。かわりに、LocalDateなどの具象型のインスタンスを作成して使い回してください。これには様々な理由がありますが、その1つはこのインタフェースの実装がISO以外の暦体系になっている可能性があることです。この問題の詳細は、ChronoLocalDateを参照してください。

## minus

```text
default Temporal minus(TemporalAmount amount)
```
```text
default Temporal minus(long amountToSubtract, TemporalUnit unit)
```

**簡単な用例**

時間的オブジェクトにTemporalAmountで表現する時間量で減算します。

```java
Period period = Period.ofDays(10);
LocalDate.of(2018, 1, 30).minus(period);
```

時間的オブジェクトにTemporalUnitで表現する単位で減算します。

```java
LocalDate.of(2018, 1, 30).minus(10, ChronoUnit.DAYS);
```

この用例でいえばよりシンプルにminusDaysを使うこともできます。

```java
LocalDate.of(2018, 1, 30).minusDays(10);
```

## plus

```text
default Temporal plus(TemporalAmount amount)
```

```text
Temporal plus(long amountToAdd, TemporalUnit unit)
```

**簡単な用例**

時間的オブジェクトにTemporalAmountで表現する時間量で加算します。

```java
Period period = Period.ofDays(10);
LocalDate.of(2018, 1, 30).plus(period);
```

時間的オブジェクトにTemporalUnitで表現する単位で加算します。

```java
LocalDate.of(2018, 1, 30).plus(10, ChronoUnit.DAYS);
```

この用例でいえばよりシンプルにplusDaysを使うこともできます。

```java
LocalDate.of(2018, 1, 30).plusDays(10);
```

## until

2つの時間的オブジェクトの間の時間量を指定した単位で計算します。

```text
long until(Temporal endExclusive, TemporalUnit unit)
```

**簡単な用例**

```java
LocalDate endExclusive = LocalDate.of(2019, 1, 1);

LocalDate.of(2018, 1, 1).until(endExclusive, ChronoUnit.DAYS);
// → 365

LocalDate.of(2018, 1, 1).until(endExclusive, ChronoUnit.MONTHS);
// → 12

LocalDate.of(2018, 1, 1).until(endExclusive, ChronoUnit.YEARS);
// → 1
```

## with

```text
default Temporal with(TemporalAdjuster adjuster)
```

```text
Temporal with(TemporalField field, long newValue)
```

**簡単な用例**

時間的オブジェクトのTemporalFieldで指定したフィールドを変更します。

```java
LocalDate.of(2018, 1, 1).with(ChronoField.MONTH_OF_YEAR, 3);
```

この用例でいえばよりシンプルにwithMonthを使うこともできます。

```java
LocalDate.of(2018, 1, 1).withMonth(3);
```

# [インタフェース TemporalAccessor] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAccessor.html)

> 時間的オブジェクト(日付、時間、オフセット、またはそれらのなんらかの組合せなど)への読取り専用アクセスを定義するフレームワークレベルのインタフェースです。

サブインターフェースにTemporalがあり、実装クラスには, LocalDate, LocalDateTime, LocalTime, Month, MonthDay, Year, YearMonthなどがあります。

> **注意**
> このインタフェースはフレームワークレベルのインタフェースであり、アプリケーション・コードで広範囲にわたって使用しないようにしてください。かわりに、LocalDateなどの具象型のインスタンスを作成して使い回してください。これには様々な理由がありますが、その1つはこのインタフェースの実装がISO以外の暦体系になっている可能性があることです。この問題の詳細は、ChronoLocalDateを参照してください。

## get

時間的オブジェクトの指定されたフィールドの値を返します。

```text
default int get(TemporalField field)
```

**簡単な用例**

```java
LocalDateTime.now().get(ChronoField.DAY_OF_MONTH);
```

この用例でいえばよりシンプルなgetDayOfMonthがあります。

```java
LocalDateTime.now().getDayOfMonth();
```

## query

時間的オブジェクトに関数型インターフェースTemporalQueryの実装を使って問い合わせをします。

```text
default <R> R query(TemporalQuery<R> query)
```

**簡単な用例**

月の最初の日曜日の週をその月の第1週として、月の第2月曜日と第3木曜日を問い合わせるクエリです。
たとえば、2018年2月の第1週は2月4日(日)から始まる週とします。（2月1日(月)は、2018年1月の第4週に含まれます。）

```java
TemporalQuery<Boolean> isRegularHoliday = accessor -> {
    LocalDate target = LocalDate.from(accessor);
    LocalDate first = target.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));
    switch (DayOfWeek.of(target.get(ChronoField.DAY_OF_WEEK))) {
        case MONDAY:
            if (target.equals(first.plusDays(8))) {
                return true;
            }
            break;
        case THURSDAY:
            if (target.equals(first.plusDays(18))) {
                return true;
            }
            break;
        default:
            break;
    }
    return false;
};

LocalDate.of(2018, 2, 5).query(isRegularHoliday);
// → false
LocalDate.of(2018, 2, 8).query(isRegularHoliday);
// → false
LocalDate.of(2018, 2,12).query(isRegularHoliday);
// → true
LocalDate.of(2018, 2,15).query(isRegularHoliday);
// → false
LocalDate.of(2018, 2,19).query(isRegularHoliday);
// → false
LocalDate.of(2018, 2,22).query(isRegularHoliday);
// → true
LocalDate.of(2018, 2,26).query(isRegularHoliday);
// → false
```

## range

時間的オブジェクトの指定したフィールドの有効な範囲を返します。（たとえば月の日数、年の日数など）

```text
default ValueRange range(TemporalField field)
```

**簡単な用例**

2020年2月の月の範囲を求めます。

```java
ValueRange range = LocalDate.of(2020, 2, 1).range(ChronoField.DAY_OF_MONTH);
range.toString();
// 1- 29
```

# [インターフェース TemporalField] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalField.html)

月、時刻などの日付/時間のフィールドを表すインターフェースで、実装クラスにEnum ChronoFieldがあります。

## adjustInto

指定した日付／時間フィールドに値を設定した新しい時間的オブジェクトを返します。

```text
<R extends Temporal> R adjustInto(R temporal, long newValue)
```

**簡単な用例**

```java
ChronoField.MONTH_OF_YEAR.adjustInto(LocalDate.now(), 12);
```

一般的な使い方として、可読性が高くなるwithを使うようにします。

```java
LocalDate.now().with(ChronoField.MONTH_OF_YEAR, 12);
```

この用例でいえばよりシンプルなwithMonthがあります。

```java
LocalDate.now().withMonth(12);
```

## [列挙型 ChronoField] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/ChronoField.html)

フィールドの標準セットです。

**定義されている主な定数(抜粋)**

* YEAR : 年
* MONTH_OF_YEAR : 月
* DAY_OF_MONTH : 月の日
* HOUR_OF_DAY : 時
* MINUTE_OF_HOUR : 分
* SECOND_OF_MINUTE : 秒
* MILLI_OF_SECOND ： 1秒のうちのミリ秒
* MICRO_OF_SECOND : 1秒のうちのマイクロ秒
* NANO_OF_SECOND : 1秒のうちのナノ秒

# [インタフェース TemporalUnit] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalUnit.html)

日間、時間などの日付/時間の単位を表すインターフェースで、実装クラスにEnum ChronoUnitがあります。

## addTo

時間的オブジェクトに日時の単位で表す時間量を加算した新しい時間オブジェクトを返します。

```text
<R extends Temporal> R addTo(R temporal, long amount)
```

**簡単な用例**

```java
ChronoUnit.DAYS.addTo(LocalDate.now(), 1);
```

一般的な使い方として、可読性が高くなるplusを使うようにします。

```java
LocalDate.now().plus(1, ChronoUnit.DAYS);
```

この用例でいえばよりシンプルなplusDaysがあります。

```java
LocalDate.now().plusDays(1);
```

## between

2つの時間的オブジェクトの間の時間量を日時の単位で表した結果を返します。

```text
long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive)
```

**簡単な用例**

```java
ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.now().plusDays(3));
```

一般的な使い方として、可読性が高くなるuntilを使うようにします。

```java
LocalDate.now().until(LocalDate.now().plusDays(3), ChronoUnit.DAYS);
// → 3
```

Periodのインスタンスを返すメソッドもあります。

```java
Period period = LocalDate.now().until(LocalDate.now().plusDays(3));
period.getDays()
// → 3
```

## isSupportedBy

時間的オブジェクトが日時の単位をサポートしているか確認します。

```text
default boolean isSupportedBy(Temporal temporal)
```

**簡単な用例**

```java
ChronoUnit.HOURS.isSupportedBy(LocalDateTime.now());
// → true
ChronoUnit.HOURS.isSupportedBy(LocalDate.now());
// → false
ChronoUnit.HOURS.isSupportedBy(LocalTime.now());
// → true
ChronoUnit.HOURS.isSupportedBy(YearMonth.now());
// → false
```

## [列挙型 ChronoUnit] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/ChronoUnit.html)

日付期間の単位の標準セットです。

**定義されている主な単位(抜粋)**

* YEARS : 1年の概念を表す単位。
* MONTHS : 1か月の概念を表す単位。
* DAYS : 1日の概念を表す単位。
* HOURS : 1時間の概念を表す単位。
* MINUTES : 1分の概念を表す単位。
* SECONDS : 1秒の概念を表す単位。
* MILLIS : 1ミリ秒の概念を表す単位 (1000分の1秒)
* MICROS : 1マイクロ秒の概念を表す単位 (100万分の1秒)
* NANOS : 1ナノ秒の概念を表す単位 (10億分の1秒)

# [インタフェース TemporalAmount] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAmount.html)

時間量を表すインターフェースで、具象クラスにはPeriod(年、月および日を格納する日付ベースの実装)、Duration(秒およびナノ秒を格納する時間ベースの実装)があります。

> **注意**
> このインタフェースはフレームワークレベルのインタフェースであり、アプリケーション・コードで広範囲にわたって使用しないようにしてください。かわりに、PeriodやDurationなどの具象型のインスタンスを作成して使い回してください。

## Periodで表す時間量の例

1日を表す時間量

```java
Period.ofDays(1);
```

1週間を表す時間量

```java
Period.ofWeeks(1);
```

1カ月と10日を表す時間量

```java
Period.ofMonths(1).plusDays(10);
```

## Durationで表す時間量の例

1時間を表す時間量

```java
Duration.ofHours(1);
```

30分を表す時間量

```java
Duration.ofMinutes(30);
```

48時間を表す時間量

```java
Duration.ofDays(2);
```

### between

Duration.betweenで2つの時間的オブジェクトの時間量を計算することができます。

```java
Duration duration = Duration.between(
    LocalDateTime.of(2018, 1, 1, 0, 0, 0),
    LocalDateTime.of(2018, 1, 2, 1, 2, 3)
);

duration.toDays();
// → 1
duration.toHours();
// → 25
duration.toMinutes();
// → 1502
duration.getSeconds();
// → 90123
```

* ちなみに、Durationクラスはjava.timeパッケージです。

## TemporalAmountを引数に取るメソッド

インタフェースTemporalAccessorを実装したクラスであればplus/minusメソッドにTemporalAmountを利用できます。

## addTo

LocalDateやLocalDateTimeなどの時間的オブジェクトにPeriodやDurationなどで表現する時間量を加算し新しい時間的オブジェクトを返します。

```text
Temporal addTo(Temporal temporal)
```

**簡単な用例**

```java
Period daysOfLimit = Period.ofDays(10);
Temporal temporal = daysOfLimit.addTo(LocalDate.of(2018, 1, 1));
LocalDate.from(temporal);
```

一般的な使い方として、可読性が高くなるplusを使うようにします。

```java
Period daysOfLimit = Period.ofDays(10);
LocalDate.of(2018, 1, 1).plus(daysOfLimit);
```

この用例でいえばよりシンプルなplusDaysがあります。

```java
LocalDate.of(2018, 1, 1).plusDays(10);
```

## subtractFrom

LocalDateやLocalDateTimeなどの時間的オブジェクトにPeriodやDurationなどで表現する時間量を減算し新しい時間的オブジェクトを返します。

```text
Temporal subtractFrom(Temporal temporal)
```

**簡単な用例**

```java
Period daysOfLimit = Period.ofDays(10);
Temporal temporal = daysOfLimit.subtractFrom(LocalDate.of(2018, 2, 1));
LocalDate.from(temporal);
```

一般的な使い方として、可読性が高くなるminusを使うようにします。

```java
Period daysOfLimit = Period.ofDays(10);
LocalDate.of(2018, 2, 1).minus(daysOfLimit);
```

この用例でいえばよりシンプルなminusDaysがあります。

```java
LocalDate.of(2018, 2, 1).minusDays(10);
```

# [インタフェース TemporalAdjuster] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAdjuster.html)

時間的オブジェクトを調整する（たとえば特定の曜日、月の第2月曜日、月末などに設定）ためのインターフェースです。
なお、一般的な時間調整（月末日を求めるなど）は、クラス
 TemporalAdjustersに実装されています。
関数型インターフェースなので、ラムダ式やメソッド参照として利用できます。

## TemporalAdjusterを引数に取るメソッド

インターフェースTemporalを実装したクラスであればwithメソッドにTemporalAdjusterを利用できます。

## adjustInto

時間的オブジェクトをアジャスタで調整した結果を新しい時間的オブジェクトとして返します。

```text
Temporal adjustInto(Temporal temporal)
```

**簡単な用例**

次の月の第2月曜日の日付を求めます。

```java
TemporalAdjuster adjuster = temporal -> {
    LocalDate target = LocalDate.from(temporal);

    // 当月の第2月曜日
    LocalDate secondMonday = target
        .with(TemporalAdjusters.firstDayOfMonth())
        .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY))
        .plusDays(7);

    if (target.isBefore(secondMonday) || target.isEqual(secondMonday)) {
        return secondMonday;
    }

    // 来月の第2月曜日
    return secondMonday
        .with(TemporalAdjusters.firstDayOfNextMonth())
        .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY))
        .plusDays(7);
};

Temporal temporal = adjuster.adjustInto(LocalDate.of(2018, 1, 1));
LocalDateTime.from(temporal);
// → 2018-01-08
```

一般的な使い方として、可読性が高くなるwithを使うようにします。

```java
LocalDatee.of(2018, 1, 29).with(adjuster);
// → 2018-02-12
```

## [クラス TemporalAdjusters] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalAdjusters.html)

一般的でよく使用される時間調整処理(たとえば月初または月末の日を求める、翌週の水曜日を求めるなど)がstaticメソッドとして実装されているクラスです。

> このクラスには、staticメソッドとして使用できるアジャスタの標準セットが含まれています。これらの機能を次に示します。
>
* 月の最初または最後の日を見つける
* 翌月の最初の日を見つける
* その年の最初または最後の日を見つける
* 翌年の最初の日を見つける
* 月内の最初または最後の曜日(「6月の最初の水曜日」など)を見つける
* 次または前の曜日(「次の木曜日」など)を見つける

**簡単な用例**

今日日付以降の次の月曜日を求めます。
当日も含めたい場合はTemporalAdjusters.nextOrSameを使用します。

```java
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));
```

月末の日付を求めます。

```java
LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
```

年末をの日付を求めます。

```java
LocalDate.now().with(TemporalAdjusters.lastDayOfYear());
```

# [インタフェース TemporalQuery\<R>] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalQuery.html)

時間的オブジェクトへの問い合わせのためのインターフェースです。
実装クラスにTemporalQueriesがあります。
関数型インターフェースなので、ラムダ式やメソッド参照として利用できます。

## TemporalQuery\<R>を引数に取るメソッド

インタフェースTemporalAccessorを実装したクラスであればqueryメソッドにラムダ式やメソッド参照を使用できます。

## queryFrom

```text
R queryFrom(TemporalAccessor temporal)
```

**簡単な用例**

次の月曜日までの日数を求めます。

```java
TemporalQuery<Long> daysOfNextMonday = accessor -> {
    LocalDate inc = LocalDate.from(accessor);
    LocalDate exc = inc.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
    return ChronoUnit.DAYS.between(inc, exc);
};

LocalDate.of(2018, 1, 29).query(daysOfNextMonday);
// → 0

LocalDate.of(2018, 1, 30).query(daysOfNextMonday);
// → 6
```

ラムダ式

```java
LocalDate.of(2018, 1, 29).query( accessor -> {
    LocalDate inc = LocalDate.from(accessor);
    LocalDate exc = inc.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    return ChronoUnit.DAYS.between(inc, exc);
});
// → 7
```

メソッド参照

```java
LocalDateTime.now().query(YearMonth::from);
// → 2018-01
```

## [クラス TemporalQueries] (https://docs.oracle.com/javase/jp/8/docs/api/java/time/temporal/TemporalQueries.html)

関数型インタフェースTemporalQueryを実装したクラスです。

### localDate

時間的オブジェクトからLocalDateを問い合わせます。

```text
public static TemporalQuery<LocalDate> localDate()
```

**簡単な用例**

```java
LocalDate date = LocalDateTime.now().query(TemporalQueries.localDate());
```

メソッド参照

```java
LocalDate date = LocalDateTime.now().query(LocalDate::from);
```

この用例でいえばよりシンプルなtoLocalDateがあります。

```java
LocalDate date = localDateTime.now().toLocalDate();
```


### localTime

時間的オブジェクトからLocalTimeを問い合わせます。

```text
public static TemporalQuery<LocalTime> localTime()
```

**簡単な用例**

```java
LocalTime time = LocalDateTime.now().query(TemporalQueries.localTime());
```

メソッド参照

```java
LocalTime time = LocalDateTime.now().query(LocalTime::from);
```

この用例でいえばよりシンプルなtoLocalTimeがあります。

```java
LocalTime time = localDateTime.now().toLocalTime();
```

# Java 9で追加されたAPI

## [パッケージ java.time.temporal] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/temporal/package-summary.html)

* モジュール: java.base

追加はありません。

## [パッケージ java.time] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/package-summary.html)

* モジュール: java.base

### [クラス Clock] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/Clock.html)

tickMillis

```text
public static Clock tickMillis​(ZoneId zone)
```

### [クラス Duration] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/Duration.html)

dividedBy

```text
public long dividedBy​(Duration divisor)
```

toSeconds

```text
public long toSeconds​()
```

toDaysPart

```text
public long toDaysPart​()
```

toHoursPart

```text
public int toHoursPart​()
```

toMinutesPart

```text
public int toMinutesPart​()
```

toSecondsPart

```text
public int toSecondsPart​()
```

toMillisPart

```text
public int toMillisPart​()
```

toNanosPart

```text
public int toNanosPart​()
```

truncatedTo

```text
public Duration truncatedTo​(TemporalUnit unit)
```

### [クラス LocalDate] ()

ofInstant

```text
public static LocalDate ofInstant​(Instant instant, ZoneId zone)
```

datesUntil

```text
public Stream<LocalDate> datesUntil​(LocalDate endExclusive)
```

datesUntil

```text
public Stream<LocalDate> datesUntil​(LocalDate endExclusive, Period step)
```

toEpochSecond

```text
public long toEpochSecond​(LocalTime time, ZoneOffset offset)
```

### [クラス LocalTime] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/LocalTime.html)

ofInstant

```text
public static LocalTime ofInstant​(Instant instant, ZoneId zone)
```

toEpochSecond

```text
public long toEpochSecond​(LocalDate date, ZoneOffset offset)
```

### [クラス OffsetTime] (https://docs.oracle.com/javase/jp/9/docs/api/java/time/OffsetTime.html)

toEpochSecond

```text
public long toEpochSecond​(LocalDate date)
```

# Java 10で追加されたAPI

## [パッケージ java.time.temporal] (https://docs.oracle.com/javase/jp/10/docs/api/java/time/temporal/package-summary.html)

* モジュール: java.base
 
追加はありません。

## [パッケージ java.time] (https://docs.oracle.com/javase/jp/10/docs/api/java/time/package-summary.html)

* モジュール: java.base

追加はありません。

# Java 14で追加されたAPI

## [パッケージ java.time.temporal] (https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/time/temporal/package-summary.html)

* モジュール: java.base
 
追加はありません。

## [パッケージ java.time] (https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/time/package-summary.html)

* モジュール: java.base

追加はありません。


# その他のおさらいメモ

* [Java NIO2のおさらいメモ] (https://qiita.com/rubytomato@github/items/6880eab7d9c76524d112)
    * 2017年08月15日
* [クラス java.util.Objectsのおさらいメモ] (https://qiita.com/rubytomato@github/items/ba38877ed5a00dd24f16)
    * 2017年08月25日
* [Java Collections Frameworkのおさらいメモ] (https://qiita.com/rubytomato@github/items/554095ae21a2c36f131a)
    * 2017年08月30日
* [パッケージ java.time.temporal のおさらいメモ] (https://qiita.com/rubytomato@github/items/e9325dd46aa11f1b8e2e)
    * 2018年01月30日
* [クラス java.util.Optionalのおさらいメモ] (https://qiita.com/rubytomato@github/items/92ac7944c830e54aa03d)
    * 2018年03月22日