一、为什么会出现新日期时间API呢?

1、面临的问题

如果我们可以跟别人说:“我们在 1502643933071 见面,别晚了!”那么就再简单不过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。 JDK 1.0 中包含了一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而 Calendar 并不比 Date 好多少。它们面临的问题是:
可变性:像日期和时间这样的类应该是不可变的。
偏移性: Date 中的年份是从 1900 开始的,而月份都从 0 开始。
格式化:格式化只对 Date 有用, Calendar 则不行。
此外,它们也不是线程安全的;不能处理闰秒等。
总结:对日期和时间的操作一直是 Java 程序员最痛苦的地方之一。

2、引入新的API

第三次引入的 API 是成功的, 并且 Java 8 中引入的 java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。

Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API
新的 java.time 中包含了所有关于 本地日期( LocalDate )、本地时间 LocalTime )、本地日期时间( LocalDateTime )、时区( ZonedDateTime 和持续时间( Duration 的类 。历史悠久的 Date 类新增了 toInstant() 方法,
用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。

二、新时间日期API

java.time 包含值对象的基础包
java.time.chrono 提供对不同的日历系统的访问
java.time.format 格式化和解析时间和日期
java.time.temporal 包括底层框架和扩展特性
java.time.zone 包含时区支持的类

说明:大多数开发者只会用到基础包和 format 包,也可能会用到 temporal 包。因此,尽管有 68 个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。

三、LocalDate、LocalTime、LocalDateTime

LocalDate LocalTime LocalDateTime 类是其中较重要的几个类,它们的实例是 不可变的对象 ,分别表示使用 ISO-8601 日历系统的日期、时间、日期和时间。
它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。

LocalDate 代表 IOS 格式( yyyy-MM-dd )的日期 , 可以存储 生日、纪念日等日期。
LocalTime 表示一个时间,而不是日期。
LocalDateTime 是用来表示日期和时间的, 这是一个最常用的类之一。

2 public void test1(){ 3 // now():获取当前的日期、时间、日期+时间 4 LocalDate localDate = LocalDate.now(); 5 LocalTime localTime = LocalTime.now(); 6 LocalDateTime localDateTime = LocalDateTime.now(); 8 System.out.println(localDate); // 2021-03-14 9 System.out.println(localTime); // 13:55:00.594 10 System.out.println(localDateTime); // 2021-03-14T13:55:00.594 12 // of():设置指定的年、月、日、时、分、秒。没有偏移量 13 LocalDateTime localDateTime1 = LocalDateTime.of(2021, 03, 14, 13, 23, 43 ); 14 System.out.println(localDateTime1); // 2021-03-14T13:23:43 16 // getXxx():获取相关的属性 17 System.out.println(localDateTime.getDayOfMonth()); // 14 18 System.out.println(localDateTime.getDayOfWeek()); // SUNDAY 19 System.out.println(localDateTime.getMonth()); // MARCH 20 System.out.println(localDateTime.getMonthValue()); // 3 21 System.out.println(localDateTime.getMinute()); // 14 23 // 体现不可变性 24 // withXxx():设置相关的属性 25 LocalDate localDate1 = localDate.withDayOfMonth(22 ); 26 System.out.println(localDate); // 2021-03-14 27 System.out.println(localDate1); // 2021-03-22 29 LocalDateTime localDateTime2 = localDateTime.withHour(4 ); 30 System.out.println(localDateTime); // 2021-03-14T14:14:50.605 31 System.out.println(localDateTime2); // 2021-03-14T04:14:50.605 33 // 不可变性 34 // plus 向对象添加 35 LocalDateTime localDateTime3 = localDateTime.plusMonths(3 ); 36 System.out.println(localDateTime); // 2021-03-14T14:14:50.605 37 System.out.println(localDateTime3); // 2021-06-14T14:14:50.605 39 // minus 从当前对象减去 40 LocalDateTime localDateTime4 = localDateTime.minusDays(6 ); 41 System.out.println(localDateTime); // 2021-03-14T14:14:50.605 42 System.out.println(localDateTime4); // 2021-03-08T14:14:50.605

四、瞬时:Instant

Instant :时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。

在处理时间和日期的时候,我们通常会想到年 , , , , , 秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。 UNIX 中,这个数从 1970 年开始,以秒为的单位;同样的,在 Java 中,也是 1970 年开始,但以毫秒为单位

java.time 包通过值类型 Instant 提供机器视图,不提供处理人类意义上的时间单位。 Instant 表示时间线上的一点,而不需要任何上下文信息,例如,时区。
概念上讲, 它只是简单的表示自 1970 1 1 0 0 0 秒( UTC )开始的秒数。 因为 java.time 包是基于纳秒计算的,所以 Instant 的精度可以达到纳秒级。

(1 ns = 10 -9 s) 1 = 1000 毫秒 =10^6 微秒 =10^9 纳秒

2、常用方法

时间戳是指格林威治时间 1970 01 01 00 00 00 ( 北京时间 1970 01 01 08 00 00 ) 起至现在的总秒数。

 1     @Test
 2     public void test2(){
 3         //now():获取本初子午线对应的标准时间
 4         Instant instant = Instant.now();
 5         System.out.println(instant);//2021-03-14T06:49:40.288Z
 7         //添加时间的偏移量 东八区
 8         OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
 9         System.out.println(offsetDateTime);//2021-03-14T14:49:40.288+08:00
11         //toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()
12         long milli = instant.toEpochMilli();
13         System.out.println(milli);  //1615704580288
15         //ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)
16         Instant instant1 = Instant.ofEpochMilli(1615704580288L);
17         System.out.println(instant1);  //2021-03-14T06:49:40.288Z

五、格式化与解析日期或时间

    java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:

    预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME;

    本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG);

    自定义的格式化。如:ofPattern("yyyy-MM-dd hh:mm:ss");

  2、常用方法

 1     @Test
 2     public void test3(){
 3         //方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
 4         DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
 5         //格式化:日期-->字符串
 6         LocalDateTime localDateTime = LocalDateTime.now();
 7         String str1 = formatter.format(localDateTime);
 8         System.out.println(localDateTime);       //2021-03-14T16:08:22.113
 9         System.out.println(str1);                //2021-03-14T16:08:22.113
11         //解析:字符串 -->日期
12         TemporalAccessor parse = formatter.parse("2021-03-14T16:08:22.113");
13         System.out.println(parse);              //{},ISO resolved to 2021-03-14T16:08:22.113
15         //方式二:
16         //本地化相关的格式。如:ofLocalizedDateTime()
17         //FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTime
18         DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
19         //格式化
20         String str2 = formatter1.format(localDateTime);
21         System.out.println(str2);//2021年3月14日 下午04时26分15秒
24         //本地化相关的格式。如:ofLocalizedDate()
25         //FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDate
26         DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
27         //格式化
28         String str3 = formatter2.format(LocalDate.now());
29         System.out.println(str3);//2021-3-14
32         //重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
33         DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
34         //格式化
35         String str4 = formatter3.format(LocalDateTime.now());
36         System.out.println(str4);//2021-03-14 04:26:15
38         //解析
39         TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");
40         System.out.println(accessor); //{SecondOfMinute=9, HourOfAmPm=3, MicroOfSecond=0, NanoOfSecond=0, MinuteOfHour=52, MilliOfSecond=0},ISO resolved to 2019-02-18

六、其他 API

  1、ZoneID 类

    该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris

    Demo:

 1     @Test
 2     public void test4() {
 3         //ZoneId:类中包含了所有的时区信息
 4         // ZoneId的getAvailableZoneIds():获取所有的ZoneId
 5         Set<String> zoneIds = ZoneId.getAvailableZoneIds();
 6         for (String s : zoneIds) {
 7             System.out.println(s);
 9         // ZoneId的of():获取指定时区的时间
10         LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
11         System.out.println(localDateTime);

  2、ZonedDateTime 类

    一个在ISO-8601日历系统时区的日期时间, 如 2007-12-03T10:15:30+01:00 Europe/Paris

    其中每个时区都对应着ID, 地区ID都为“ {区域}/{城市}” 的格式, 例如:Asia/Shanghai

    Demo:

 1     @Test
 2     public void test5() {
 3         //ZonedDateTime:带时区的日期时间
 4         // ZonedDateTime的now():获取本时区的ZonedDateTime对象
 5         ZonedDateTime zonedDateTime = ZonedDateTime.now();
 6         System.out.println(zonedDateTime);   //2021-03-14T16:57:12.169+08:00[Asia/Shanghai]
 7         // ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
 8         ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
 9         System.out.println(zonedDateTime1); //2021-03-14T17:57:12.169+09:00[Asia/Tokyo]

  3、Clock 类

    使用时区提供对当前即时、 日期和时间的访问的时钟。

    Demo:

 1 public static void main(String[] args) {
 2         Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
 3         for (String string : availableZoneIds) {
 4             System.out.println(string);
 7         ZonedDateTime t = ZonedDateTime.now();
 8         System.out.println(t);
10         ZonedDateTime t1 = ZonedDateTime.now(ZoneId.of("America/New_York"));
11         System.out.println(t1);
13 //        Clock clock = Clock.systemDefaultZone();
14         Clock c = Clock.system(ZoneId.of("America/New_York"));
15         System.out.println(c.getZone());
16         System.out.println(c.instant());
17     }
2 public void test6() { 3 //Duration:用于计算两个“时间”间隔,以秒和纳秒为基准 4 LocalTime localTime = LocalTime.now(); 5 LocalTime localTime1 = LocalTime.of(15, 23, 32); 6 //between():静态方法,返回Duration对象,表示两个时间的间隔 7 Duration duration = Duration.between(localTime1, localTime); 8 System.out.println(duration); //PT1H34M59.713S 9 System.out.println(duration.getSeconds()); //5699 10 System.out.println(duration.getNano()); //713000000 11 LocalDateTime localDateTime = LocalDateTime.of(2016, 6, 12, 15, 23, 32); 12 LocalDateTime localDateTime1 = LocalDateTime.of(2017, 6, 12, 15, 23, 32); 13 Duration duration1 = Duration.between(localDateTime1, localDateTime); 14 System.out.println(duration1.toDays()); //-365

  5、Period 类:日期间隔

    用于计算两个“日期” 间隔

    Demo:

 1     @Test
 2     public void test7() {
 3         //Period:用于计算两个“日期”间隔,以年、月、日衡量
 4         LocalDate localDate = LocalDate.now();
 5         LocalDate localDate1 = LocalDate.of(2028, 3, 18);
 6         Period period = Period.between(localDate, localDate1);
 7         System.out.println(period);                  //P7Y4D
 8         System.out.println(period.getYears());       //7
 9         System.out.println(period.getMonths());      //0
10         System.out.println(period.getDays());        //4
11         Period period1 = period.withYears(2);
12         System.out.println(period1);                 //P2Y4D

  6、TemporalAdjuster

         时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。

    Demo:

 1 @Test
 2     public void test8() {
 3         // TemporalAdjuster:时间校正器
 4         // 获取当前日期的下一个周日是哪天?
 5         TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
 6         LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
 7         System.out.println(localDateTime);   //2021-03-21T17:19:33.279
 8         // 获取下一个工作日是哪天?
 9         LocalDate localDate = LocalDate.now().with(new TemporalAdjuster() {
10             @Override
11             public Temporal adjustInto(Temporal temporal) {
12                 LocalDate date = (LocalDate) temporal;
13                 if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
14                     return date.plusDays(3);
15                 } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
16                     return date.plusDays(2);
17                 } else {
18                     return date.plusDays(1);
19                 }
20             }
21         });
22         System.out.println("下一个工作日是: " + localDate);   //下一个工作日是: 2021-03-15

  7、TemporalAdjusters 

    该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。

与传统日期处理的转换