Java 8的一个新特性,引入了新的时间和日期API ,我们可以借助新的时间和API来更方便地处理时间日期

  1. Java的java.util.Date和java.util.Calendar类易用性差,不支持时区,不支持国际化,而且他们都不是线程安全的;
  2. Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,用于格式化日期的类DateFormat被放在3. java.text包中,它是一个抽象类,所以我们需要实例化一个SimpleDateFormat对象来处理日期格式化,并且DateFormat也是非线程安全;
  3. 对日期的计算方式繁琐,而且容易出错,因为月份是从0开始的,从Calendar中获取的月份需要加一才能表示当前月份。
    java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。

Java 8日期/时间API是JSR-310的实现,它的实现目标是克服旧的日期时间实现中所有的缺陷,新的日期/时间API的一些设计原则是:

  1. 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。
  2. 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日 期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。
  3. 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。
  4. 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。
  5. 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。
  • java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是这个包的一部分,如:LocalDate, LocalTime, - - LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在绝大多数情况下,这些类能够有效地处理一些公共的需求。
  • java.time.chrono包:这个包为非ISO的日历系统定义了一些泛化的API,我们可以扩展AbstractChronology类来创建自己的日历系统。同时java8提供了4套日历:

    • ThaiBuddhistDate:泰国佛教历
    • MinguoDate:中华民国历
    • JapaneseDate:日本历
    • HijrahDate:伊斯兰历
  • java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为- - java.time包中相应的类已经提供了格式化和解析的方法。
  • java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式。
  • java.time.zone包:这个包包含支持不同时区以及相关规则的类。

LocalDate:

LocalDate是一个不可变的类,它表示默认格式(yyyy-MM-dd)的日期,我们可以使用now()方法得到当前时间,也可以提供输入年份、月份和日期的输入参数来创建一个LocalDate实例。

now():方法都会获取到当前的时间。该类为now()方法提供了重载方法,我们可以传入ZoneId来获得指定时区的日期。
of():方法会要求传入对应的 年月日时分秒 的信息,来返回对应的时间.
ofYearDay():表示某一年的第几天,它会计算好对应的天数并且返回对应的日期.
ofEpochDay():表示1970-1-1开始后的多少天的日期

//输出当前的系统日期
System.out.println(LocalDate.now());
//输出指定某个时区的日期
System.out.println(LocalDate.now(ZoneId.of("Asia/Tokyo")));
//传入对应的年月日,输出日期
System.out.println(LocalDate.of(2019, Month.JANUARY, 1));
//从1970-1-1开始后的多少天的日期
System.out.println(LocalDate.ofEpochDay(365));
//某一年的第几天的日期
System.out.println(LocalDate.ofYearDay(2019, 100));
System.out.println("\n");

LocalTime:

LocalTime是一个不可变的类,它的实例代表一个符合人类可读格式的时间,默认格式是hh:mm:ss.zzz。像LocalDate一样,该类也提供了时区支持,同时也可以传入小时、分钟和秒等输入参数创建实例,of和now方法和LocalDate类似。

now():输出当前系统时间
ofSecondOfDay():表示一天开始以秒计时的时间
of():传入指定时分秒,转成时间

//输出当前的系统时间
System.out.println(LocalTime.now());
//输出指定某个时区的时间
System.out.println(LocalTime.now(ZoneId.of("Asia/Tokyo")));
//传入指定时分秒,转成时间
System.out.println(LocalTime.of(4,5,6));

LocalDateTime:

LocalDateTime是一个不可变的日期-时间对象,它表示一组日期-时间,默认格式是yyyy-MM-dd-HH-mm-ss.zzz。它提供了一个工厂方法,接收LocalDate和LocalTime输入参数,创建LocalDateTime实例。它可以通过of()方法直接创建,也可以调用LocalDate的atTime()方法或LocalTime的atDate()方法将LocalDate或LocalTime合并成一个LocalDateTime

//输出指定某个时区的日期时间
System.out.println(LocalDateTime.now(ZoneId.of("Asia/Tokyo")));
//传入对应的年月日时分秒,得到日期时间
System.out.println(LocalDateTime.of(2019, Month.MAY, 4, 17, 23, 52));
//LocalDate转LocalDateTime
System.out.println(LocalDate.now()
        .atTime(LocalTime.now()));
//LocalTime转LocalDateTime
System.out.println(LocalTime.now()
        .atDate(LocalDate.now()));

时间转换:

你可以把某个格式的时间转成LocalDateTime或者LocalDate,LocalTime
他们都有parse方法,parse方法被重载,既可以接收一个时间字符串,也可以接收一个时间字符串和DateTimeFormatter(时间格式)。如果没有传时间格式就是默认的格式,默认格式见上文。传入时间格式也就是可以自定义从某个格式转成LocalDateTime

//解析yyyy-MM-dd格式的时间转成LocalDate对象
System.out.println(LocalDate.parse("2019-03-11"));
//解析HH:mm:ss格式的时间转成LocalTime对象:
System.out.println(LocalTime.parse("12:11:11"));
//解析yyyy-MM-dd-HH-mm-ss.zzz格式的时间转成LocalDateTime对象:
System.out.println(LocalDateTime.parse("2019-03-11T12:11:11.550"));
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss");
//解析非默认的yyyy-MM-dd HH-mm-ss格式的时间转成LocalDateTime对象:
System.out.println(LocalDateTime.parse("2019-03-11 12-11-11", dateTimeFormatter));

前后加减日期时间操作:

可以对年、月、日、周进行加减法运算: 如果加(或减)日期超过当月的最大天数(或小于等于0)则月份对应增加(或减少); 如果加(或减)月份超过12(或小于等于0)则年份对应增加(或减少); 加减周数其实是对日期(天数)的加减;
TemporalAdjusters类中包含了很多静态方法可以直接使用,具体API移步:http://www.matools.com/api/java8

方法
方法

如果上面表格中列出的方法不能满足你的需求,你还可以创建自定义的TemporalAdjuster接口的实现,TemporalAdjuster也是一个函数式接口,所以我们可以使用Lambda表达式:

@FunctionalInterface
public interface TemporalAdjuster {
    Temporal adjustInto(Temporal temporal);
}

比如给定一个日期,计算该日期的下一个工作日(不包括星期六和星期天):

LocalDate date = LocalDate.of(2019, 5, 27);
date.with(temporal -> {
    // 当前日期
    DayOfWeek dayOfWeek = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
 
    // 正常情况下,每次增加一天
    int dayToAdd = 1;
 
    // 如果是星期五,增加三天
    if (dayOfWeek == DayOfWeek.FRIDAY) {
        dayToAdd = 3;
    }
 
    // 如果是星期六,增加两天
    if (dayOfWeek == DayOfWeek.SATURDAY) {
        dayToAdd = 2;
    }
 
    return temporal.plus(dayToAdd, ChronoUnit.DAYS);
});

其他API:

DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//减法
//获取当前日期
System.out.println(LocalDate.now()
        .format(dateTimeFormatter1));
//获取当前日期的前一天
System.out.println(LocalDate.now()
        .minusDays(1)
        .format(dateTimeFormatter1));
//获取当前日期的前一月
System.out.println(LocalDate.now()
        .minusMonths(1)
        .format(dateTimeFormatter1));
//获取当前日期的前一周
System.out.println(LocalDate.now()
        .minusWeeks(1)
        .format(dateTimeFormatter1));
//获取当前日期往后一个月
System.out.println(LocalDate.now()
        .plusMonths(1)
        .format(dateTimeFormatter1));
System.out.println("\n");
 
//加法
//获取当前日期后一天
System.out.println(LocalDate.now()
        .plusDays(1)
        .format(dateTimeFormatter1));
//获取当前日期的后一周
System.out.println(LocalDate.now()
        .plusWeeks(1)
        .format(dateTimeFormatter1));
//获取当前日期的后一月
System.out.println(LocalDate.now()
        .plusMonths(1)
        .format(dateTimeFormatter1));
//获取当前日期的后一年
System.out.println(LocalDate.now()
        .plusYears(1)
        .format(dateTimeFormatter1));
 
//当前日期时间的前一天
String lastDayOfNow = LocalDateTime.now()
        .minusDays(1)
        .format(dateTimeFormatter);
System.out.println(lastDayOfNow);
//当前日期时间的前一月
String lastMonthOfNow = LocalDateTime.now()
        .minusMonths(1)
        .format(dateTimeFormatter);
System.out.println(lastMonthOfNow);
//当前日期时间的前一周
String lastWeekOfNow = LocalDateTime.now()
        .minusWeeks(1)
        .format(dateTimeFormatter);
System.out.println(lastWeekOfNow);
//当前日期时间的前一小时
String lastHourOfNow = LocalDateTime.now()
        .minusHours(1)
        .format(dateTimeFormatter);
System.out.println(lastHourOfNow);
//当前日期时间的前一秒
String lastSecondOfNow = LocalDateTime.now()
        .minusSeconds(1)
        .format(dateTimeFormatter);
System.out.println(lastSecondOfNow);
 
// 取本月第1天:
LocalDate firstDayOfThisMonth = LocalDate.now()
        .with(TemporalAdjusters.firstDayOfMonth());
System.out.println(firstDayOfThisMonth);
// 取本月第2天:
LocalDate secondDayOfThisMonth = LocalDate.now()
        .withDayOfMonth(2);
System.out.println(secondDayOfThisMonth);
// 取本月最后一天,再也不用计算是28,29,30还是31:
LocalDate lastDayOfThisMonth = LocalDate.now()
        .with(TemporalAdjusters.lastDayOfMonth());
System.out.println(lastDayOfThisMonth);
// 取下一天:
LocalDate firstDayOfNextMonth = lastDayOfThisMonth.plusDays(1);
System.out.println(firstDayOfNextMonth);
// 取2019年5月第一个周一
LocalDate firstMondayOf2019 = LocalDate.parse("2019-05-01")
        .with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println(firstMondayOf2019);
 
//把时间部分置0
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime midnight = LocalDateTime.now()
        .withHour(0)
        .withMinute(0)
        .withSecond(0);
System.out.println(midnight.format(formatter));
//替换日期为1
System.out.println(LocalDateTime.now().withDayOfMonth(1));
//替换天数为1
System.out.println(LocalDateTime.now().withDayOfYear(1));
//替换月份为1:
System.out.println( LocalDateTime.now().withMonth(1));
//替换年份为1
System.out.println( LocalDateTime.now().withYear(1));

获取指定时间的日期

LocalTime中预定义了不少静态变量如MIDNIGHT,NOON标记了是什么时间

//获取当天午夜00-00-00的日期时间
LocalTime midTime = LocalTime.MIDNIGHT;
LocalDate today = LocalDate.now();
LocalDateTime todayMidnight = LocalDateTime.of(today, midTime);
System.out.println(todayMidnight);
//等价于
LocalDateTime todayMidnight1 = today.atTime(midTime);
System.out.println(todayMidnight1);
//等价于
LocalDateTime atStartOfDay = LocalDate.now()
        .atStartOfDay();
System.out.println("一天的开始:" + atStartOfDay.format(formatter));
 
//明天午夜00-00-00的日期时间
LocalDateTime tomorrowMidnight = todayMidnight.plusDays(1);
System.out.println(tomorrowMidnight);
//中午时间 比如一天的中午时间-》操作类似上文
System.out.println(LocalTime.NOON);

格式化日期

新的日期API中提供了一个DateTimeFormatter类用于处理日期格式化操作,它被包含在java.time.format包中,Java 8的日期类有一个format()方法用于将日期格式化为字符串,该方法接收一个DateTimeFormatter类型参数

LocalDateTime dateTime = LocalDateTime.now();
//使用预定义的格式
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(strDate1);
//自定义格式
String strDate2 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
System.out.println(strDate2);
String strDate3 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE));
System.out.println(strDate3);
String strDate4=DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM dd日 E").format(LocalDateTime.now());
System.out.println(strDate4);

时间点 Instant

在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数。这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
java.time 包通过值类型Instant提供机器视图。Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。因为java.time包是基于纳秒计算的,所以Instant类的精度可以达到纳秒级。

Instant instant = Instant.now();
//UTC当前时间转时间戳(毫秒)
System.out.println(instant.toEpochMilli());
//UTC当前时间转时间戳(秒)
System.out.println(instant.getEpochSecond());
//时间戳(秒)转UTC时间
System.out.println(Instant.ofEpochSecond(1558968257));

Instant典型的用法是,当你需要记录事件的发生时间,而不需要记录任何有关时区信息时,存储和比较时间戳。
Instant很多有趣的地方在于,你不能对它做什么,而不是你能做什么。例如,下面的几行代码会抛出异常:

instant.get(ChronoField.MONTH_OF_YEAR);
instant.plus(6, ChronoUnit.YEARS);

抛出这些异常是因为,Instant只包含秒数和纳秒数,不提供处理人类意义上的时间单位。如果确实有需要,你需要额外提供时区信息。
另外Instant也是新时间LocalDateTime此类和Date旧时间的转换中介,如Date有toInstant()可以将旧时间类向新时间类迁移

//Date to Instant
Instant timestamp = new Date().toInstant();
//Now we can convert Instant to LocalDateTime or other similar classes
LocalDateTime date5 = LocalDateTime.ofInstant(timestamp,
        ZoneId.of(ZoneId.SHORT_IDS.get("PST")));
System.out.println("Date = "+date5);
 
//Calendar to Instant
Instant time = Calendar.getInstance().toInstant();
System.out.println(time);
//TimeZone to ZoneId
ZoneId defaultZone = TimeZone.getDefault().toZoneId();
System.out.println(defaultZone);
 
//ZonedDateTime from specific Calendar
ZonedDateTime gregorianCalendarDateTime = new GregorianCalendar().toZonedDateTime();
System.out.println(gregorianCalendarDateTime);
 
//Date API to Legacy classes
Date dt = Date.from(Instant.now());
System.out.println(dt);
 
TimeZone tz = TimeZone.getTimeZone(defaultZone);
System.out.println(tz);
 
GregorianCalendar gc = GregorianCalendar.from(gregorianCalendarDateTime);
System.out.println(gc);

时区

Java 8中的时区操作被很大程度上简化了,新的时区类java.time.ZoneId是原有的java.util.TimeZone类的替代品。ZoneId对象可以通过ZoneId.of()方法创建,也可以通过ZoneId.systemDefault()获取系统默认时区。
我们上面所看到的LocalDate/LocalDateTime/LocalTime类不包含时区的信息。如果我们想要在一个特定的时区使用date/time,我们可以使用ZonedDateTime或OffsetDateTime

of()方法接收一个“区域/城市”的字符串作为参数,你可以通过getAvailableZoneIds()方法获取所有合法的“区域/城市”字符串:

System.out.println(ZoneId.getAvailableZoneIds());
 
ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");
System.out.println(shanghaiZoneId);
ZoneId systemZoneId = ZoneId.systemDefault();
System.out.println(systemZoneId);

对于老的时区类TimeZone,Java 8也提供了转化方法,toZoneId():
ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();
有了ZoneId,我们就可以将一个LocalDate、LocalTime或LocalDateTime对象转化为ZonedDateTime对象:
ZoneId oldToNewZoneId = TimeZone.getDefault().toZoneId();
将zonedDateTime打印到控制台为:

2017-01-05T15:26:56.147+08:00[Asia/Shanghai]

ZonedDateTime对象由两部分构成,LocalDateTime和ZoneId,其中2017-01-05T15:26:56.147部分为LocalDateTime,+08:00[Asia/Shanghai]部分为ZoneId。
另一种表示时区的方式是使用ZoneOffset,它是以当前时间和世界标准时间(UTC)/格林威治时间(GMT)的偏差来计算。那么他们有什么区别?
引用javadoc中的介绍

OffsetDateTime, ZonedDateTime and Instant all store an instant on the time-line to nanosecond precision. Instant is the simplest, simply representing the instant. OffsetDateTime adds to the instant the offset from UTC/Greenwich, which allows the local date-time to be obtained. ZonedDateTime adds full time-zone rules
从上段说明知道OffsetDateTime和ZonedDateTime之间的差异在于后者包括涵盖夏令时调整的规则。
It is intended that ZonedDateTime or Instant is used to model data in simpler applications. This class may be used when modeling date-time concepts in more detail, or when communicating to a database or in a network protocol.

至于为什么在写数据库是采用OffsetDateTime

One reason is that dates with local time offsets always represent the same instants in time, and therefore have a stable ordering. By contrast, the meaning of dates with full timezone information is unstable in the face of adjustments to the rules for the respective timezones. (And these do happen…)

参见:https://stackoverflow.com/questions/30234594/whats-the-difference-between-java-8-zoneddatetime-and-offsetdatetime
从a转换ZonedDateTime为OffsetDateTime将考虑夏令时,而从另一个方向转换OffsetDateTime为ZonedDateTime,意味着您不会获得有关该区域的信息,也不会在那里是适用于夏令时的任何规则。这是因为偏移不定义任何时区规则,也不会绑定到特定区域。

//偏移量
ZoneOffset offset = ZoneOffset.of("+07:00");
//当前日历系统中与UTC/Greenwich的偏移量的日期时间
OffsetTime time = OffsetTime.now();
System.out.println(time);
//返回具有指定偏移量的此OffsetDateTime的副本,确保结果处于同一时刻。
OffsetTime sameTimeDifferentOffset = time.withOffsetSameInstant(
        offset);
System.out.println(sameTimeDifferentOffset);
//返回具有指定偏移量的此OffsetDateTime的副本,确保结果具有相同的本地日期时间。
OffsetTime changeTimeWithNewOffset = time.withOffsetSameLocal(
        offset);
System.out.println(changeTimeWithNewOffset);
//更改时间以及秒数
System.out.println(changeTimeWithNewOffset
        .withHour(3)
        .plusSeconds(2));

也可以把Instant时间通过ZoneId转成LocalDateTime

Instant instant = Instant.now();
LocalDateTime dateTime1 = LocalDateTime.ofInstant(instant, ZoneId.of("America/Cuiaba"));
System.out.println(dateTime1);

时间长度

Period用来表示两个LocalDate之间的时间差。Period类表示以年、月、日衡量的时长
Period.between()是计算两个时间在一个周期内相差天数,如一个月内,一周内,即30天,7天为一个周期内相差的天数,如2017-03-10与2017-04-10这之间的时间能正常计算出相差的天数,但如果相差大于一个周期(月,周)等则会出现问题,并不是实际相差的天数,通过beforeDate.until(nowDate, ChronoUnit.DAYS)可获取实际相差天数

LocalDate today1 = LocalDate.now();
LocalDate yesterday = LocalDate.of(today1.getYear(), today1.getMonth(), today1.getDayOfMonth() - 1);
Period period = yesterday.until(today1);
System.out.println("period: " + period);
//等价于
period = Period.between(yesterday, today1);
System.out.println("period: " + period);
System.out.println(period.isNegative());
System.out.println(period.getDays());
 
//util与period.between的区别
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDate nowDate3= LocalDate.parse("2017-04-06 14:30:47", formatter2);
LocalDate beforeDate =LocalDate.parse("2017-03-06 14:30:47", formatter2);
int diffDays = Period.between(beforeDate, nowDate3).getDays();
 
System.out.println(diffDays);
System.out.println(beforeDate.until(nowDate3, ChronoUnit.DAYS));
System.out.println(beforeDate.until(nowDate3).getDays());

Duration表示Instant之间的时间差,可以用来统计任务的执行时间,也支持各种运算操作,Duration类表示以秒和纳秒为基准的时长。例如,“23.6秒”。
Duration的内部实现与Instant类似,也是包含两部分:seconds表示秒,nanos表示纳秒。两者的区别是Instant用于表示一个时间戳(或者说是一个时间点),而Duration表示一个时间段,所以Duration类中不包含now()静态方法。可以通过Duration.between()方法创建Duration对象

//计算两个时间相差的秒数
long secs = ChronoUnit.SECONDS.between(midnight, LocalDateTime.now());
System.out.println(secs);
long nanos = Duration.between(midnight, LocalDateTime.now()).toNanos();
long secs1 = TimeUnit.NANOSECONDS.toSeconds(nanos);
System.out.println(secs1);
 
//计算两个时间的相差的分钟数
long minits = ChronoUnit.MINUTES.between(midnight, LocalDateTime.now());
System.out.println(minits);
long minits1 = Duration.between(midnight, LocalDateTime.now()).toMinutes();
System.out.println(minits1);
 
//计算两个时间的相差的小时数
long hours = ChronoUnit.HOURS.between(midnight, LocalDateTime.now());
System.out.println(hours);
long hours1 = Duration.between(midnight,LocalDateTime.now()).toHours();
System.out.println(hours1);

它们可以作为参数,传给主要的时间/日期类的增加或减少时间的方法:

Period sixMonths = Period.ofMonths(6);
System.out.println(sixMonths);
LocalDate date1 = LocalDate.now();
LocalDate future = date1.plus(sixMonths);
System.out.println(future);
Duration duration=Duration.ofDays(3);
LocalDateTime localDateTime1=LocalDateTime.now().plus(duration);
System.out.println(localDateTime1);
Duration duration=Duration.ofDays(3);
LocalDateTime localDateTime1=LocalDateTime.now().plus(duration);
System.out.println(localDateTime1);

时间格式缩写

参见java.time.format包下的描述,在此不再详述
参考:http://www.matools.com/api/java8

https://my.oschina.net/mcyy568/blog/809608

http://www.importnew.com/14140.html

https://lw900925.github.io/java/java8-newtime-api.html

https://github.com/bingbo/blog/wiki/Java8%E6%97%A5%E6%9C%9F%E6%97%B6%E9%97%B4API

https://community.oracle.com/docs/DOC-887401

http://kael-aiur.com/java/java8%E4%B8%AD%E7%9A%84time%E5%8C%85.html

http://www.leftso.com/blog/378.html