Javaで日時を扱う（Java8）

Java8では、日時を扱うクラス群が様変わりしてしまいました。これを機に、日時の扱いをまとめてみたいと思います。[前回](http://qiita.com/kurukurupapa@github/items/b52dee4935a6434d006b)は、Java7までの日時、今回は、Java8での日時を書きました。

Java8では、Java7までのDate,Calendarの代替として、次のクラスなどが導入されましたね。

 * Instant - 日時（エポック秒）
 * LocalDateTime - タイムゾーンなし日時
 * ZonedDateTime - タイムゾーンあり日時

# 現在/指定日時の作成
Instantクラスの現在/指定日時を作成する。

```java
// 現在日時
Instant nowInstant = Instant.now();
// long→Instant
Instant instant2 = Instant.ofEpochMilli(msec1);
// LocalDateTime→Instant
Instant instant3b = localDt1.toInstant(ZoneId.systemDefault().getRules().getOffset(Instant.EPOCH));
// ZonedDateTime→Instant
Instant instant4ca = zonedDt1.toInstant();
Instant instant4cb = Instant.from(zonedDt1);
// 文字列→Instant
Instant instant5 = Instant.parse("2007-12-03T10:15:30.00Z");
```

LocalDateTimeクラスの現在/指定日時を作成する。

```java
// 現在日時
LocalDateTime nowLocalDt = LocalDateTime.now();
// 指定日時
LocalDateTime localDt2 = LocalDateTime.of(2016, 5, 2, 15, 0, 0);
// long→LocalDateTime
LocalDateTime localDt3 = LocalDateTime.ofInstant(Instant.ofEpochMilli(msec1), ZoneId.systemDefault());
// Instant→LocalDateTime
LocalDateTime localDt4 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault());
// ZonedDateTime→LocalDateTime
LocalDateTime localDt5a = zonedDt1.toLocalDateTime();
LocalDateTime localDt5b = LocalDateTime.from(zonedDt1);
// 文字列→LocalDateTime
LocalDateTime localDt6a = LocalDateTime.parse("2007-12-03T10:15:30.123");
LocalDateTime localDt6b = LocalDateTime.parse("2007/12/03 10:15:30.123",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS"));
```

ZonedDateTimeの現在/指定日時を作成する。

```java
// 現在日時
ZonedDateTime nowZonedDt = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
// 指定日時
ZonedDateTime zonedDt2 = ZonedDateTime.of(2016, 5, 2, 15, 0, 0, 0, ZoneId.of("Asia/Tokyo"));
// long→ZonedDateTime
ZonedDateTime zonedDt3 = ZonedDateTime.ofInstant(Instant.ofEpochMilli(msec1), ZoneId.systemDefault());
// Instant→ZonedDateTime
ZonedDateTime zonedDt4a = instant1.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDt4b = ZonedDateTime.ofInstant(instant1, ZoneId.systemDefault());
// LocalDateTime→ZonedDateTime
ZonedDateTime zonedDt5a = localDt1.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDt5b = ZonedDateTime.ofLocal(localDt1, ZoneId.systemDefault(), null);
// 文字列→ZonedDateTime型
ZonedDateTime zonedDt6a = ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]");
ZonedDateTime zonedDt6b = ZonedDateTime.parse("2016/05/02 10:15:30 Asia/Tokyo",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss VV"));
ZonedDateTime zonedDt6c = ZonedDateTime.parse("2016/05/02 10:15:30 JST",
		DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss zzz"));
```

文字列の現在/指定日時を作成する。

```java
// Instant→文字列
String instantStr1 = DateTimeFormatter.ISO_INSTANT.format(instant1);
String instantStr2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS")
		.format(LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()));
// LocalDateTime→文字列
String localStr1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS").format(localDt1);
// ZonedDateTime→文字列
// "xxxxx VV" - （例）"+09:00 Asia/Tokyo"
// "xxxx zzz" - （例）"+0900 JST"
String zonedStr1a = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSxxxxx VV").format(zonedDt1);
String zonedStr1b = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSSxxxx zzz").format(zonedDt1);
```

# 日時から日付/時刻の取り出し

```java
// Instant 日時→日付
Instant ymdInstant1 = instant1.truncatedTo(ChronoUnit.DAYS);

// LocalDateTime 日時→日付、時刻
LocalDate localDate1 = localDt1.toLocalDate();
LocalTime localTime1 = localDt1.toLocalTime();

// ZonedDateTime 日時→日付、時刻
ZonedDateTime ymdZoned1 = zonedDt1.truncatedTo(ChronoUnit.DAYS);
LocalDate localDate2 = zonedDt1.toLocalDate();
LocalTime localTime2 = zonedDt1.toLocalTime();
```

# 曜日の取得

```java
// Instant→曜日
String instantWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE)
		.format(LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()));
String instantWeek2 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault()).getDayOfWeek()
		.getDisplayName(TextStyle.FULL, Locale.JAPANESE);

// LocalDateTime→曜日
// ※"E","EEEE"は、タイムゾーンによって曜日の表記が変わる。
String localWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE).format(localDt1);
String localWeek2 = localDt1.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPANESE);

// ZonedDateTime→曜日
// ※"E","EEEE"は、タイムゾーンによって曜日の表記が変わる。
String zonedWeek1 = DateTimeFormatter.ofPattern("E, EEEE", Locale.JAPANESE).format(zonedDt1);
String zonedWeek2 = zonedDt1.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.JAPANESE);
```

# 日時計算
加算/減算

```java
// LocalDateTime 1秒後、1日後、１ヶ月後
LocalDateTime localNextSec = localDt1.plusSeconds(1);
LocalDateTime localNextDay = localDt1.plusDays(1);
LocalDateTime localNextMonth = localDt1.plusMonths(1);
// ZonedDateTime 1秒後、1日後、１ヶ月後
ZonedDateTime zonedNextSec = zonedDt1.plusSeconds(1);
ZonedDateTime zonedNextDay = zonedDt1.plusDays(1);
ZonedDateTime zonedNextMonth = zonedDt1.plusMonths(1);
```

月初/月末を求める。

```java
// LocalDateTime 月初、月末
LocalDateTime localMonthBeginning = localDt1.with(TemporalAdjusters.firstDayOfMonth());
LocalDateTime localMonthEnd = localDt1.with(TemporalAdjusters.lastDayOfMonth());
// ZonedDateTime 月初、月末
ZonedDateTime zonedMonthBeginning = zonedDt1.with(TemporalAdjusters.firstDayOfMonth());
ZonedDateTime zonedMonthEnd = zonedDt1.with(TemporalAdjusters.lastDayOfMonth());
```

差を求める。

```java
// LocalDateTime 日時の差 ミリ秒単位、日数単位（切り捨て）
long localDiffMsec = ChronoUnit.MILLIS.between(localDt1, localNextDay);
long localDiffDays1 = ChronoUnit.DAYS.between(localDt1, localNextDay);
long localDiffDays2 = ChronoUnit.DAYS.between(localDt1.toLocalDate(), localNextDay.toLocalDate());
// LocalDateTime 日時の差 時分秒単位、年月日単位
Duration localDuration = Duration.between(localDt1, localNextDay);
Period localPeriod = Period.between(localDt1.toLocalDate(), localNextDay.toLocalDate());
// ZonedDateTime 日時の差 ミリ秒単位、日数単位（切り捨て）
long zonedDiffMsec = ChronoUnit.MILLIS.between(zonedDt1, zonedNextDay);
long zonedDiffDays1 = ChronoUnit.DAYS.between(zonedDt1, zonedNextDay);
long zonedDiffDays2 = ChronoUnit.DAYS.between(zonedDt1.toLocalDate(), zonedNextDay.toLocalDate());
// ZonedDateTime 日時の差 時分秒単位、年月日単位
Duration zonedDuration = Duration.between(zonedDt1, zonedNextDay);
Period zonedPeriod = Period.between(zonedDt1.toLocalDate(), zonedNextDay.toLocalDate());
```

比較する。

```java
// LocalDateTime
boolean localAfterFlag = localNextDay.isAfter(localDt1);
// ZonedDateTime
boolean zonedAfterFlag = zonedNextDay.isAfter(zonedDt1);
```

# 参考

 * Java日付処理メモ(Hishidama's Java Date Memo) http://www.ne.jp/asahi/hishidama/home/tech/java/date.html
 * 日時に関する情報を取得する(get) - Calendarクラス http://www.javadrive.jp/start/calendar/index2.html
 * Java日付時刻APIメモ(Hishidama's Java8 Date and Time API Memo) http://www.ne.jp/asahi/hishidama/home/tech/java/datetime.html
 * Java日付時刻フォーマッターメモ(Hishidama's Java8 DateTimeFormatter Memo) http://www.ne.jp/asahi/hishidama/home/tech/java/DateTimeFormatter.html