Java
java8
SimpleDateFormat
DateFormatter

java8の日付時間が新しくなったよ

JDK1.8前の日付時間クラス

Date

jdk1.0から提供されている日付時間クラスで、エポックからのミリ秒ヲ保持している。
「GMT 1970年1月1日 0時0分0秒からの現在に至るミリ秒」
Y2k問題や性能面の問題があるので、メソッドは殆ど非推奨(@Deprecated)されていている。

生き残っているコントラクターとメソッド
// 生成
Date d1 = new Date();
Date d2 = new Date(System.currentTimeMillis() + 1);

// before,after
System.out.println(d1.after(d2));
System.out.println(d1.before(d2));

// set,get
d1.setTime(System.currentTimeMillis() + 1);
d2.setTime(System.currentTimeMillis() - 1);
System.out.println(d1.getTime());
System.out.println(d2.getTime());

Dateのy2k問題

y2k問題
System.out.println(new Date(10, 1, 1));

⇒ 1910年1月1日になってしまう。

Date.java
public Date(int year, int month, int date, int hrs, int min, int sec) {
   int y = year + 1900; // <- ここ
   // 略
}

Calendar

Date.javaの欠陥を改善したもので、名前の通りカレンダーを表現しているクラス。
1. Calendarクラスは、年月日時分秒ミリ秒のフィールドを持っている。
protected int fields[];

  1. 抽象クラスであり、(多分)Tmeplate Methodパターンで実装されており、 サブクラスを実装することで世界各地で使うカレンダーの差異を吸収している。 例:和暦、旧暦

Calendar のコアAPI

API 概要
Calendar カレンダーの(抽象)親クラス
TimeZone 時間帯を表す
Locale 地域を表して、これによって生成されるCalendarが異なる

Caldendar生成

表示用
private static void show(Calendar cal) {
    System.out.println("生成されたカレンダー : " + cal.getClass().getName());
    System.out.println(
        cal.get(Calendar.YEAR) + "年"
        + (cal.get(Calendar.MONTH) + 1) + "月"
        + cal.get(Calendar.DAY_OF_MONTH) + "日 "
        + cal.get(Calendar.HOUR_OF_DAY) + "時"
        + cal.get(Calendar.MINUTE) + "分"
        + cal.get(Calendar.SECOND) + "秒");
}
生成
Calendar デフォルトカレンダー = Calendar.getInstance();
show(デフォルトカレンダー);

Calendar 和暦_デフォルト時間帯 = Calendar.getInstance(new Locale("ja", "JP", "JP"));
show(和暦_デフォルト時間帯);

Calendar デフォルト地域_JST = Calendar.getInstance(TimeZone.getTimeZone("JST"));
show(デフォルト地域_JST);

Calendar 和暦_GMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"), new Locale("ja", "JP", "JP"));
show(和暦_GMT);
出力
生成されたカレンダー : java.util.GregorianCalendar
2017年11月13日 12時20分0秒
生成されたカレンダー : java.util.JapaneseImperialCalendar
29年11月13日 12時20分0秒
生成されたカレンダー : java.util.GregorianCalendar
2017年11月13日 12時20分0秒
生成されたカレンダー : java.util.JapaneseImperialCalendar
29年11月13日 3時20分0秒
  1. GregorianCalendar、デフォルト地域で生成される
  2. JapaneseImperialCalendar、地域を日本にすることで生成される
    Japanese-Calendar.PNG

Calendar <=> Date

Calendar,Date変換
// Date to Calendar
Calendar.getInstance().setTime(new Date());
// Calendar to Date
Calendar.getInstance().getTime();

add()とroll()の違い

add()とroll()両方指定フィールド(年月日時分秒ミリ秒)を増減するためのものだが、

  上位 下位
add() 上位を変更する 最小変更にする
roll() 上位を変更しない 最小変更にする
add()
Calendar calendar = Calendar.getInstance();
calendar.set(2015, Calendar.NOVEMBER,  30);
System.out.println("初期値 : " + formatter.format(calendar.getTime()));

calendar.add(Calendar.MONTH, 3);
System.out.println("add : " + formatter.format(calendar.getTime()));

2015/11/30 -> add 月+3 -> 2016/2/29

roll()
Calendar calendar = Calendar.getInstance();
calendar.set(2015, Calendar.NOVEMBER,  30);
System.out.println("初期値 : " + formatter.format(calendar.getTime()));

calendar.roll(Calendar.MONTH, 3);
System.out.println("roll : " + formatter.format(calendar.getTime()));

2015/11/30 -> roll 月+3 -> 2015/2/28

Lenient(寛大さ)&遅延

SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
Calendar calendar = Calendar.getInstance();
calendar.set(2015, 15,  32);
System.out.println(formatter.format(calendar.getTime()));  // 2016/05/02

calendar.setLenient(false);
calendar.set(2015, 15,  32);
// Exception in thread "main" java.lang.IllegalArgumentException: MONTH
System.out.println(formatter.format(calendar.getTime()));
出力
2016/05/02
Exception in thread "main" java.lang.IllegalArgumentException: MONTH
  1. Lenientのデフォルトはtrueなので、2015/15/32 -> 2016/05/02を容認する
  2. Lenient=falaseで、月=15を容認しないから
  3. 例外はsetではなく、get()で発生する。
    set()は遅延されて、無駄な計算が行われなくするため。

JDK1.8の日付時間クラス

本題!!
JKD1.8からjava.timeパッケージに日付時間のクラスが数多く追加されている。

コアAPI
jdk8-datetime-class (1).png

コアAPI

日付時間のコアAPI 概要
TemporalAccessor 日付、時間、オフセット、またはそれらのなんらかの組合せなどへの読取り専用アクセスを定義したインタフェースです。
Temporal 日付、時間、オフセット、またはそれらのなんらかの組合せなどへの読取/書込アクセスを定義したインタフェースです。
TemporalAmount 時間の量を定義したインタフェースです。
TemporalField 日付時間のフィールドを定義したインタフェースです。
TemporalUnit 日付時間の単位を定義したFunctionalインタフェースです。
TemporalAdjuster 日付時間調整戦略を提供するためのFunctionalインタフェースです。
TemporalQuery 日付時間にアクセスする戦略を提供するためのFunctionalインタフェースです。

TemporalAccessor

TemporalAccessorメソッド 結果
TemporalAccessor temporalAccessor = LocalDate.of(2016, 2, 9) 2016-02-09
temporalAccessor.get(ChronoField.YEAR) 2016
temporalAccessor.getLong(ChronoField.MONTH_OF_YEAR) 2
temporalAccessor.isSupported(ChronoField.HOUR_OF_DAY) false
temporalAccessor.range(ChronoField.DAY_OF_MONTH) 1 - 29
temporalAccessor.query(TemporalQueries.precision()) Days
  1. TemporalAccessorを実装したLocalDateでインスタンスを取得してます。
  2. TemporalFieldを実装したChronoFieldで使って年フィールドを取得します。
  3. TemporalQueryの実装返すTemporalQueries.zoneId()を使って精度を取得してます。

Temporal

Temporalは、TemporalAccessorを継承して、書込みインタフェースを追加してます。

Temporalメソッド 結果
Temporal temporal = LocalDate.of(2016, 10, 1) 2016-10-01
temporal.plus(10, ChronoUnit.MONTHS) 2017-08-01
temporal.minus(Period.ofYears(1)) 2015-10-01
temporal.minus(2, ChronoUnit.YEARS) 2014-10-01
temporal.with(ChronoField.YEAR, 2010) 2010-10-01
temporal.with(LocalDate.of(2010, 1, 10)) 2010-01-10
temporal.until(LocalDate.of(2016, 1, 1), ChronoUnit.DAYS) -274
  1. TemporalAmountを実装したPeriodで加算、減算してます。
  2. TemporalUnitを実装したChronoUnitで加算、減算してます。
  3. TemporalFieldを実装したChronoField年フィールドを調整してます。
  4. temporal.with(LocalDate.of(2010, 1, 10))のLocalDate.of(2010, 1, 10)はTemporalAdjusterにキャストされます。

TemporalAmount

TemporalAmountメソッド 結果
TemporalAmount temporalAmount = Duration.ofDays(61) P61D
temporalAmount.getUnits() [Years, Months, Days]
temporalAmount.get(ChronoUnit.DAYS) 61
temporalAmount.get(ChronoUnit.MONTHS) 0
temporalAmount.subtractFrom(LocalDate.of(2010, 10, 1)) 2010-08-01
temporalAmount.addTo(LocalDate.of(2010, 10, 1)) 2010-12-01
  1. TemporalAmountを実装したDurationインスタンス取得してます。
  2. TemporalUnitを実装したChronoUnitで値を取得してます。

TemporalField

TemporalFieldメソッド 結果
TemporalField year = ChronoField.YEAR Year
year.range() -999999999 - 999999999
year.getBaseUnit() Years
year.getDisplayName(Locale.JAPAN)
year.getFrom(LocalDate.of(2011, 1, 10)) 2011
year.getRangeUnit() Forever
year.isDateBased() true
year.isTimeBased() false

TemporalFieldを実装したChronoFieldでインスタンスを取得してます。

TemporalUnit

TemporalUnitメソッド 結果
TemporalUnit days = ChronoUnit.DAYS Days
days.addTo(LocalDate.of(2011, 1, 1), 2) 2011-01-03
days.getDuration() PT24H
days.isSupportedBy(LocalDate.now()) true
days.isDurationEstimated() true
days.isDateBased() true
days.isTimeBased() false

TemporalAdjuster&TemporalAdjusters

TemporalAdjusterメソッド 結果
TemporalAdjuster adjuster = LocalDate.of(2011, 1, 1) 2011-01-01
adjuster.adjustInto(LocalDate.of(9999, 10, 1)) 2011-01-01

TemporalAdjustersは色んな時間調整戦略を提供します。

TemporalAdjusters 結果
LocalDate.of(2011, 1, 1).with(TemporalAdjusters.lastDayOfYear()) 2011-12-31
LocalDate.of(2011, 1, 1).with(TemporalAdjusters.lastDayOfMonth()) 2011-01-31

TemporalQuery, TemporalQueries

例:年末まで何日残っているか?

TemporalQuery<Long> leftDays = temporal -> {
    LocalDate dayOfTarget = LocalDate.from(temporal);
    LocalDate lastDayOfYear = dayOfTarget.with(TemporalAdjusters.lastDayOfYear());
    Period period = dayOfTarget.until(lastDayOfYear);
    return ChronoUnit.DAYS.between(dayOfTarget, lastDayOfYear);
};
System.out.println(
    LocalDate.of(2015, 10, 3).query(leftDays)
);

TemporalQueriesは色んなアクセス戦略を提供します。
例:オブジェクトの精度はなんだ?

LocalDate.of(2015, 10, 3).query(TemporalQueries.precision())

日付時間の実装

Instant

  1. エポック秒(1970-01-01T00:00:00Zから経過時間)を表現する不変&スレッドセーフクラス。
  2. ナノ秒まで保持する。
  3. Temporal, TemporalAdjusterを継承してます。
インスタンス取得 toString()
Instant.now() 2017-11-14T01:47:25.392Z
Instant.now(Clock.systemUTC()) 2017-11-14T01:47:25.486Z
Instant.now(Clock.system(ZoneId.of("Asia/Shanghai"))) 2017-11-14T01:47:25.502Z
Instant.parse("2016-10-10T10:20:30.123Z") 2016-10-10T10:20:30.123Z
Instant.EPOCH 1970-01-01T00:00:00Z
Instant.ofEpochMilli(10) 1970-01-01T00:00:00.010Z
Instant.ofEpochSecond(1) 1970-01-01T00:00:01Z
Instant.ofEpochSecond(1, 2) 1970-01-01T00:00:01.000000002Z
常用メソッド 結果
Instant instant = Instant.parse("2016-10-10T10:00:00.000Z") 2016-10-10T10:00:00Z
instant.toEpochMilli() 1476093600000
instant.plusSeconds(30) 2016-10-10T10:00:30Z
instant.minusSeconds(30) 2016-10-10T09:59:30Z
instant.isAfter(instant) false
instant.isBefore(instant) false
instant.equals(instant) true

LocalDate

タイムゾーンなし日付(yyyy-mm-dd)を表現する不変&スレッドセーフクラスです。
誕生日などに使えます。

インスタンス取得 toString()
LocalDate.now() 2017-11-14
LocalDate.now(Clock.systemUTC()) 2017-11-14
LocalDate.now(ZoneId.of("Europe/Paris")) 2017-11-14
LocalDate.of(2015, 10, 1) 2015-10-01
LocalDate.parse("2015 - 10 - 10") 2015-10-10
LocalDate.ofYearDay(2016, 60) 2016-02-29
常用メソッド toString()
LocalDate.of(2010, 2, 3).getYear() 2010
LocalDate.of(2010, 2, 3).getMonth() FEBRUARY
LocalDate.of(2010, 2, 3).getDayOfMonth() 3
LocalDate.of(2010, 3, 3).getDayOfWeek() WEDNESDAY
LocalDate.of(2010,1,1).withMonth(3).withYear(2016).withDayOfMonth(15) 2016-03-15
LocalDate.of(2010,1,1).withYear(2016).withDayOfYear(59) 2016-02-28
LocalDate.of(2010,1,1).minusYears(1).minusMonths(2).minusDays(3) 2008-10-29
LocalDate.of(2010,1,1).plusYears(1).plusMonths(2).plusDays(3) 2011-03-04

LocalTime

タイムゾーンなし(HH:mm:ss.SSSSSSSSS)を表現する不変&スレッドセーフクラスです。

インスタンス取得 toString()
LocalTime.now() 12:06:40.790
LocalTime.now(Clock.systemUTC()) 03:06:40.805
LocalTime.now(ZoneId.of("Europe/Paris")) 04:06:40.868
LocalTime.of(6, 10, 30) 06:10:30
LocalTime.parse("10:20:30") 10:20:30
LocalTime.of(6, 10, 30, 999999999) 06:10:30.999999999
常用メソッド toString()
LocalTime.of(10, 20, 30).getHour() 10
LocalTime.of(10, 20, 30).getSecond() 30
LocalTime.of(10, 20, 30).getMinute() 20
LocalTime.of(10, 20, 30).withHour(11).withMinute(22).withSecond(33).withNano(44) 11:22:33.000000044
LocalTime.of(10, 20, 30).minusHours(1).minusMinutes(1).minusSeconds(1).minusNanos(1) 09:19:28.999999999
LocalTime.of(10, 20, 30).plusHours(1).plusMinutes(1).plusSeconds(1).plusNanos(1) 11:21:31.000000001

LocalDateTime

LocalDateとLocalTimeを内部で持っていて、
タイムゾーンなし日付時間(yyyy-mm-dd HH:mm:ss.SSSSSSSSS)を表現する不変&スレッドセーフクラスです。

LocalDataTime.java
/**
 * The date part.
 */
private final LocalDate date;
/**
 * The time part.
 */
private final LocalTime time;
インスタンス取得 toString()
LocalDate.now() 2017-11-14T12:45:41.756
LocalDate.now(Clock.systemUTC()) 2017-11-14T03:45:41.756
LocalDate.now(ZoneId.of("Europe/Paris")) 2017-11-14T04:45:41.834
LocalDateTime.of(2010, 10, 1, 10, 20, 30, 123456789) 2010-10-01T10:20:30.123456789
ZonedDateTime.parse("2010-10-01T10:20:30.123456789") 2010-10-01T10:20:30.123456789
常用メソッド toString()
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getYear() 2010
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getMonth() OCTOBER
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getDayOfMonth() 1
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getDayOfYear() 274
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getHour() 10
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getMinute() 20
LocalDateTime.of(2010, 10, 1, 10, 20, 30).getSecond() 30
LocalDateTime.of(2010, 10, 1, 10, 20, 30).plusYears(1) 2011-10-01T10:20:30
LocalDateTime.of(2010, 10, 1, 10, 20, 30).minusYears(1) 2009-10-01T10:20:30

ZoneDateTime

タイムゾーン付き(HH:mm:ss.SSSSSSSSS)を表現する不変&スレッドセーフクラスです。
基本的な使い方は、LocalTimeDateと変わらないようです。

インスタンス取得 toString()
ZonedDateTime.now() 2017-11-14T12:53:12.536+09:00[Asia/Tokyo]
ZonedDateTime.now(Clock.systemUTC()) 2017-11-14T03:53:12.536Z
ZonedDateTime.now(ZoneId.of("Europe/Paris")) 2017-11-14T04:53:12.598+01:00[Europe/Paris]
ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("Asia/Shanghai")) 2017-11-14T12:53:12.614+08:00[Asia/Shanghai]
ZonedDateTime.of(2010, 10, 1, 10, 20,30, 999, ZoneId.of("Asia/Tokyo")) 2010-10-01T10:20:30.000000999+09:00[Asia/Tokyo]
ZonedDateTime.parse("2010-10-01T10:20:30.000000999+09:00[Asia/Tokyo]") 2010-10-01T10:20:30.000000999+09:00[Asia/Tokyo]
常用メソッド toString()
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getYear() 2010
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getMonth() OCTOBER
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getDayOfMonth() 1
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getDayOfYear() 274
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getHour() 10
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getMinute() 20
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).getSecond() 30
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).plusYears(1) 2011-10-01T10:20:30.000000999+09:00[Asia/Tokyo]
ZonedDateTime.of(2010, 10, 1, 10, 20, 30, 999, ZoneId.of("Asia/Tokyo")).minusYears(1) 2009-10-01T10:20:30.000000999+09:00[Asia/Tokyo]

OffsetDateTime

LocalDateTimeとOffsetを組み合わせたものです。

https://docs.oracle.com/javase/jp/8/docs/api/java/time/OffsetDateTime.html
「OffsetDateTime、ZonedDateTime、およびInstantはすべて、時系列上のインスタントをナノ秒の精度まで格納します。Instantはもっとも単純で、単にインスタントを表します。OffsetDateTimeは、UTC/グリニッジからのオフセットをインスタントに加算して、ローカル日付/時間を取得できるようにします。ZonedDateTimeは完全なタイムゾーン・ルールを追加します。」

OffsetDateTime.java
/**
 * The local date-time.
 */
private final LocalDateTime dateTime;
/**
 * The offset from UTC/Greenwich.
 */
private final ZoneOffset offset;

YearMonth、MonthDay

YearMonth : yyyy-mmを表現する不変&スレッドセーフクラスです。
MonthDay : mm-ddを表現する不変&スレッドセーフクラスです。

YearMonth インスタンス取得 toString()
YearMonth.now() 2017-11
YearMonth.now(Clock.systemUTC()) 2017-11
YearMonth.now(ZoneId.of("Europe/Paris")) 2017-11
YearMonth.of(2011, 10) 2011-10
YearMonth.parse("2012-10") 2012-10
YearMonth 常用メソッド toString()
YearMonth.of(2011, 10).getYear() 2011
YearMonth.of(2011, 10).getMonth() OCTOBER
YearMonth.of(2011, 10).plusMonths(2) 2011-12
YearMonth.of(2011, 10).minusYears(3) 2008-10
MonthDay インスタンス取得 toString()
MonthDay.now() --11-14
MonthDay.now(Clock.systemUTC()) --11-14
MonthDay.now(ZoneId.of("Europe/Paris")) --11-14
MonthDay.of(5, 10) --05-10
MonthDay.parse("--05-10") --05-10
MonthDay 常用メソッド toString()
MonthDay.of(5, 10).getMonth() MAY
MonthDay.of(5, 10).getDayOfMonth() 10
MonthDay.of(5, 10).with(Month.JANUARY).withDayOfMonth(20) --01-20

Year

Year : yyyyを表現する不変&スレッドセーフクラスです。

インスタンス取得 toString()
Year.now() 2017
Year.now(Clock.systemUTC()) 2017
Year.now(ZoneId.of("Europe/Paris")) 2017
Year.of(2011) 2011
Year.parse("2012") 2012
常用メソッド toString()
Year.of(2011).getValue() 2011
Year.of(2011).plusYears(3) 2014
Year.of(2011).minusYears(10) 2001

Month、DayOfWeek

Month、月を表現する列挙体
DayOfWeek、曜日を表す列挙体

Monthインスタンス取得 toString()
Month.of(10) OCTOBER
Month.valueOf("JANUARY") JANUARY
Month.FEBRUARY FEBRUARY
Month常用メソッド toString()
Month.of(1).getValue() 1
Month.of(12).plus(3) MARCH
Month.of(3).minus(4) NOVEMBER
DayOfWeekインスタンス取得 toString()
DayOfWeek.of(1) MONDAY
DayOfWeek.valueOf("FRIDAY") FRIDAY
DayOfWeek.FRIDAY FRIDAY
DayOfWeek常用メソッド toString()
DayOfWeek.of(1).getValue() 1
DayOfWeek.of(1).plus(7) MONDAY
DayOfWeek.of(1).minus(7) MONDAY

Clock

タイムゾーン付システム時刻を表現するクラスです。
日付時間クラスのnow()は、このClockを元に生成します。

Clock取得

Clock clockDefault = Clock.systemDefaultZone();  

defalut-clock-1.gif

UTC時計
Clock clockUTC = Clock.systemUTC();  

UTC-Clock2.gif

タイムゾーン指定時計
Clock clockParis= Clock.system(ZoneId.of("Europe/Paris"));

clock-paris.gif

Clockは時計なので、時間は進みます

※gifで取得した理由

時間は進む
Clock clock = Clock.systemDefaultZone();
System.out.println(clock.instant());
Thread.sleep(1000 * 2);
System.out.println(clock.instant());
2017-11-13T11:41:27.548Z
2017-11-13T11:41:29.551Z

特殊な時計取得

止まっている時計
Clock fixedClock = Clock.fixed(Instant.now(), ZoneId.of("Asia/Tokyo"));
System.out.println("fixed clock : " + fixedClock.instant());
Thread.sleep(1000 * 2);
System.out.println("fixed clock : " + fixedClock.instant());
結果
fixed clock : 2017-11-13T11:46:01.224Z
fixed clock : 2017-11-13T11:46:01.224Z

⇒ 時計が進みません。
テスト時刻を止まっている時計を活用してUTを行うとよいそうです。

秒時計
Clock secondsTickClock = Clock.tickSeconds(ZoneId.of("Asia/Tokyo"));
System.out.println("seconds tick clock : " + secondsTickClock.instant());
Thread.sleep(1000 * 2);
System.out.println("seconds tick clock : " + secondsTickClock.instant());
結果
seconds tick clock : 2017-11-13T11:52:20Z
seconds tick clock : 2017-11-13T11:52:22Z

⇒ 秒刻みで、秒以下は保持しない

分時計
Clock minutesTickClock = Clock.tickMinutes(ZoneId.of("Asia/Tokyo"));
System.out.println("minutes tick clock : " + minutesTickClock.instant());
Thread.sleep(1000 * 2);
System.out.println("minutes tick clock : " + minutesTickClock.instant());
結果
minutes tick clock : 2017-11-13T11:52:00Z
minutes tick clock : 2017-11-13T11:52:00Z

⇒ 分刻みで、秒以下は保持しない

指定時間量分進んだ時計
Clock nowClock = Clock.systemDefaultZone();
Clock offsetClock = Clock.offset(nowClock, Duration.ofDays(1));
System.out.println("nowClock : " + nowClock.instant());
System.out.println("offsetClock : " + offsetClock.instant());
結果
nowClock : 2017-11-13T11:58:25.647Z
offsetClock : 2017-11-14T11:58:25.647Z

⇒ 1日進んだ時計

TemporalAmount

Duration

時間量を表現する不変&スレッドセーフクラスです。
※ 単位はSeconds, Nanos

インスタンス取得 結果
Duration.ofDays(2) PT48H
Duration.ofHours(3) PT3H
Duration.ofMinutes(40) PT40M
Duration.parse("PT15M") PT15M
常用メソッド 結果
Duration.ofDays(3).getUnits() [Seconds, Nanos]
Duration.ofDays(3).toHours() 72
Duration.ofDays(3).toMinutes() 4320
DDuration.ofDays(3).toMillis() 259200000
Duration.ofDays(3).plusDays(1) PT96H
Duration.ofDays(3).plusDays(-1) PT48H

Period

時間量を表現する不変&スレッドセーフクラスです。
※ 単位はYears, Months, Days

インスタンス取得 結果
Period.ofDays(2) P2D
Period.ofMonths(3) P3M
Period.ofYears(4) P4Y
Period.parse("P4Y") P4Y
常用メソッド 結果
Period.ofYears(3).getDays() 0
Period.ofYears(3).getMonths() 0
Period.ofYears(3).getYears() 3
Period.ofYears(3).getUnits() [Years, Months, Days]
Period.ofDays(3).plusDays(1) P4D
Period.ofDays(3).minusDays(1) P2D

ZoneId

時間帯を表現するクラス

ZoneId.systemDefault();
ZoneId.getAvailableZoneIds();
ZoneId.of("Asia/Tokyo");

日付時間クラス間の変換

変換メソッド 変換後クラス
MonthDay.of(10, 1).atYear(2015) java.time.LocalDate
YearMonth.of(2015, 10).atDay(30) java.time.LocalDate
YearMonth.of(2015, 10).atEndOfMonth() java.time.LocalDate
LocalTime.now().atDate(LocalDate.now()) 2017-11-14T14:41:28.728
LocalDate.now().atTime(10, 20) java.time.LocalDateTime
LocalDate.now().atStartOfDay() java.time.LocalDateTime
LocalDate.now().atStartOfDay(ZoneId.of("Asia/Shanghai")) java.time.ZonedDateTime
LocalDateTime.now().atZone(ZoneId.of("Asia/Shanghai")) java.time.ZonedDateTime
LocalDateTime.now().toLocalDate() java.time.LocalDate
LocalDateTime.now().toLocalTime() java.time.LocalTime
LocalDateTime.now().toInstant(ZoneOffset.UTC) java.time.Instant
ZonedDateTime.now().toLocalDateTime() java.time.LocalDateTime
ZonedDateTime.now().toLocalDate() java.time.LocalDate
ZonedDateTime.now().toInstant() java.time.Instant
Instant.now().atZone(ZoneId.of("Asia/Shanghai")) java.time.ZonedDateTime
Instant.now().atOffset(ZoneOffset.UTC) java.time.OffsetDateTime

日付時間フォーマット

DateFormat

jdk1.0??から提供されていて、下記二つの要素でフォーマットを制御している。
1. LONG,FULL,MEDIUM.SHORT
2. Locale

もう使わないだろう?!

インスタンス生成&format&parse toString()
DateFormat.getDateInstance(DateFormat.FULL, Locale.JAPAN).format(new Date()) 2017年11月14日
DateFormat.getTimeInstance(DateFormat.FULL, Locale.US).format(new Date()) 4:56:05 PM JST
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.CHINA).format(new Date()) 2017-11-14 下午4:56
DateFormat.getDateInstance(DateFormat.FULL, Locale.JAPAN).parse("2017年11月14日") Tue Nov 14 00:00:00 JST 2017
DateFormat.getTimeInstance(DateFormat.FULL, Locale.US).parse("4:52:25 PM JST") Thu Jan 01 16:52:25 JST 1970
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.CHINA).parse("2017-11-14 下午4:52") Tue Nov 14 16:52:00 JST 2017

SimpleDateFormat

馴染み深い日付フォーマッタですね!!
DateFormmatのサブクラスで、pattern文字列でフォーマットを決める。

インスタンス生成&format&parse toString()
new SimpleDateFormat("yyyy-MM-dd").format(new Date()) 2017-11-14
new SimpleDateFormat("yyyy年MM月dd HH時mm分ss秒だよ").format(new Date()) 2017年11月14 17時24分11秒だよ
new SimpleDateFormat("yyyy-MM-dd").parse("2017-11-14") Tue Nov 14 00:00:00 JST 2017
タイムゾーンを設定できる
SimpleDateFormat s1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat s2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
s2.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
System.out.println(s1.format(new Date()));
System.out.println(s2.format(new Date()));
出力
2017/11/14 17:26:53
2017/11/14 16:26:53

DateTimeFormatter

JKD1.8から日付時間クラスと一緒に追加されたものです。
java.time.formatパッケージに入っており、DateFormatとSimpleDateFormatを合体したようなもの?

format
DateTimeFormatter[] formatters = {
    DateTimeFormatter.ISO_DATE,
    DateTimeFormatter.ISO_LOCAL_DATE,
    DateTimeFormatter.ISO_LOCAL_DATE_TIME,
    DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM),
    DateTimeFormatter.ofPattern("Gyyyy/MM/dd HH::mm:ss.SSS")
};
LocalDateTime localDateTime = LocalDateTime.now();
Arrays.stream(formatters)
    .forEach(
        formatter ->
            System.out.println(formatter.format(localDateTime))
    );
Arrays.stream(formatters)
    .forEach(
        formatter ->
            System.out.println(localDateTime.format(formatter))
    );
parse
 // 日付時刻#parse
 LocalDate.parse("2015/10/10", DateTimeFormatter.ofPattern("yyyy/MM/dd"));

 // DateTimeFormatter#parse
 DateTimeFormatter.ofPattern("yyyy/MM/dd").parse("2015/10/10");
 DateTimeFormatter.ofPattern("yyyy/MM/dd").parse("2015/10/10", TemporalQueries.localDate());

可読性の観点からは日付時刻#parseが推奨されてます。