3.1_28 JavaSE-JDK8新特性 P4 【Date】新日期API

相关链接


目录


1. 旧API问题


 Java自带的 java.util.Date,自Java1.0开始使用

java.util.Date
在这里插入图片描述

 从Java1.1开始,Date类中的所有方法就已被弃用,标记为@Deprecated
  原因: 1. 线程不安全的风险,在并发编程中可能会出现bug
      2. 日期计算困难
      3. API使用不规范
在这里插入图片描述 Java1.1推荐采用 java.util.Calendar 类处理日期和时间,但是这个类同样存在不少问题


a.计算困难

需求: 计算2021年1月1日到现在(2022年1月17日)相差几天

java.util.Calendar 的set方法,month:规定0代表1月,不符合常理
在这里插入图片描述
在这里插入图片描述

案例代码一老版本API存在问题  a.计算困难

package com.groupies.jdk8.day04;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * @author GroupiesM
 * @date 2022/01/17
 * @introduction 老版本API存在问题 a.计算困难
 * 需求:计算2021年1月1日到现在相差几天
 */
public class Demo1DateTimeCalculate {
    public static void main(String[] args) {
        //获取2022年1月1日 Date
        Calendar c = Calendar.getInstance();
        c.set(2022, 0, 1);
        Date d1 = c.getTime();
        long s1 = d1.getTime();

        //获取2022年1月17日 Date
        Date d2 = new Date();
        long s2 = d2.getTime();

        //计算相差天数 (毫秒->天)
        long intervalDay1 = (s2 - s1) / 1000 / 60 / 60 / 24;
        System.out.println("2022年1月1日距离现在已经过了" + intervalDay1 + "天");

        //Java8新版本的API完成需求
        long intervalDay2 = ChronoUnit.DAYS.between(LocalDate.of(2022, 1, 1), LocalDate.now());
        System.out.println("2022年1月1日距离现在已经过了" + intervalDay2 + "天");
    }
}

b.线程不安全

需求: 创建十个线程,将字符串 2022-01-01 01:01:01 转换为Date对象后打印到控制台上

案例代码二老版本API存在问题  b.线程不安全

package com.groupies.jdk8.day04;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author GroupiesM
 * @date 2022/01/17
 * @introduction 
 */
public class Demo2DateFormatUnSafe {
    final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        //循环10次,创建10个线程对象并启动
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    Date date = SIMPLE_DATE_FORMAT.parse("2022-01-01 01:01:01");
                    System.out.println(date);
                } catch (ParseException e) {e.printStackTrace();}
            }).start();
        }
    }
}

执行结果:
在这里插入图片描述

Exception in thread "Thread-3" Exception in thread "Thread-7" Exception in thread "Thread-6" java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:601)
	at java.lang.Long.parseLong(Long.java:631)
	at java.text.DigitList.getLong(DigitList.java:195)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.groupies.jdk8.day04.Demo2DateFormatUnSafe.lambda$main$0(Demo2DateFormatUnSafe.java:20)
	at java.lang.Thread.run(Thread.java:748)
Exception in thread "Thread-8" java.lang.NumberFormatException: empty String
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
	at java.lang.Double.parseDouble(Double.java:538)
	at java.text.DigitList.getDouble(DigitList.java:169)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.groupies.jdk8.day04.Demo2DateFormatUnSafe.lambda$main$0(Demo2DateFormatUnSafe.java:20)
	at java.lang.Thread.run(Thread.java:748)
java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:601)
	at java.lang.Long.parseLong(Long.java:631)
	at java.text.DigitList.getLong(DigitList.java:195)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.groupies.jdk8.day04.Demo2DateFormatUnSafe.lambda$main$0(Demo2DateFormatUnSafe.java:20)
	at java.lang.Thread.run(Thread.java:748)
java.lang.ArrayIndexOutOfBoundsException: -1
	at java.text.DigitList.fitsIntoLong(DigitList.java:230)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2082)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.groupies.jdk8.day04.Demo2DateFormatUnSafe.lambda$main$0(Demo2DateFormatUnSafe.java:20)
	at java.lang.Thread.run(Thread.java:748)
Sat Jan 01 01:01:01 CST 2022
Sat Jan 01 01:01:01 CST 2022
Sat Jan 01 01:01:01 CST 2022
Fri Jun 11 11:01:01 CST 2190
Sat Jan 01 01:01:01 CST 2022
Sat Jan 01 01:01:01 CST 2022

异常原因: 全局使用同一个calendar对象,如果没有线程同步措施,可能会造成线程安全问题

在这里插入图片描述

解决方案: 同步代码块,或升级为Java8新版本日期API

        //循环10次,创建10个线程对象并启动
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    synchronized (SIMPLE_DATE_FORMAT){
                        Date date = SIMPLE_DATE_FORMAT.parse("2022-01-01 01:01:01");
                        System.out.println(date);
                    }
                } catch (ParseException e) {e.printStackTrace();}
            }).start();
        }
    }

c.API使用不规范

  月份从0开始计算,这里的8表示是9月;即month比实际月份少1,而year和date和实际日期是相同的;

在这里插入图片描述

  JavaSE8 引入的 java.time 包解决了这些问题。java.time 包基于Joda-Time库构件,是一种免费的开源解决方案,在Java8没有出现之前,公司中已经广泛使用Joda-Time来解决Java中的日期与时间问题,Joda-Time的设计团队也参与了 java.time 包的开发。


2. 新API概览⭐️

  Date-Time API中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化。(通过now方法根据当前日期或时间创建实例)


2.1 时间点类【按API功能类型分】

id类名作用
1Instant  格林威治时间戳,表示0时区的当前系统时间,可以使用Instant类作为中间类完成 旧版本日期API -> 新版本日期API 的转换。
  默认格式: 年-月-日T时:分:秒.纳秒Z
  实例: 2022-01-17T09:59:21.814Z
--------------------------------------------------------------------------------------
  通以下形式可以完成旧版本API的升级
  Date date = new java.util.Date();
  Instant instant = date.toInstant();
--------------------------------------------------------------------------------------
  Z 表示zulu time,即祖鲁时间,又被称为 格林威治标准时间(GMT)、世界时(UT),是在英格兰格林威治零度经线的时间。
  祖鲁时间比美国中部标准时间晚6个小时,比美国中部夏季时(Daylight-Savings Time)晚5个小时。
  祖鲁时间在世界范围内是相同的,因此通讯网络的交换也是按照祖鲁时间为标准来协调的。
2 Enum DayOfWeek  一个不可变的日期时间对象,表示星期几
  默认格式: 英文大写
  实例: MONDAY
3MonthDay  一个不可变的日期时间对象,表示月日
  默认格式: –月-日
  实例: --01-17
4 Enum Month  一个不可变的日期时间对象,表示
  默认格式: 英文大写
  实例: JANUARY
5YearMonth  一个不可变的日期时间对象,表示年月
  默认格式: 年-月
  实例: 2022-01
6Year  一个不可变的日期时间对象,表示
  默认格式:
  实例: 2022
7LocalTime  一个不可变的日期时间对象,表示本地时间
  默认格式: 时:分:秒.纳秒
  实例: 17:59:21.988
8LocalDate  一个不可变的日期时间对象,表示本地日期
  默认格式: 年-月-日
  实例: 2022-01-17
9LocalDateTime  一个不可变的日期时间对象,表示本地日期时间
  还可以访问其他日期和时间字段,例如:DayOfWeek,Month等。
  默认格式: 年-月-日T时:分:秒.纳秒
  实例: 2022-01-17T17:59:21.988
在这里插入图片描述
--------------------------------------------------------------------------------------
  LocalDateTime 表示 ISO-8601日历系统中不带时区的日期时间。
  说明: ISO-8601日系统是现今世界上绝大部分国家/地区使用的,这就是我们国人所说的公历,有闰年的特性。
10OffsetDateTime  一个不可变的日期时间对象,表示偏移的日期时间
  还可以访问其他日期和时间字段,例如:DayOfWeek,Month等。
  默认格式: 年-月-日T时:分:秒.纳秒±偏移时间
  实例: 2022-01-17T17:59:21.989+08:00
11ZonedDateTime  一个不可变的日期时间对象,表示具有时区的日期时间,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。
  还可以访问其他日期和时间字段,例如:DayOfWeek,Month等
  默认格式: 年-月-日T时:分:秒.纳秒±偏移时间[时区]
  实例: 2022-01-17T17:59:21.989+08:00[Asia/Shanghai]
在这里插入图片描述

2.2 时间段类【按API功能类型分】

id类名作用
12Duration  TemporalAmount 接口的实现类,表示秒或纳秒时间间隔,适合处理需要时间高精确性的场景(秒杀)。(常用 l. 时间间隔 between:作为Duration.between静态方法的参数。)
13Period  TemporalAmount 接口的实现类,表示一段时间(年、月、日)。(常用 l. 时间间隔 between:作为Duration.between静态方法的参数。e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  实例: 获取距离今天1年2个月零3天以后的本地日期时间
      LocalDateTime result = LocalDateTime.now().plus(Period.of(1, 2, 3));
--------------------------------------------------------------------------------------
  TemporalUnit是个接口,一般直接使用该接口在Java8自带的实现类即可(Duration、Period)
  idea查看uml图方式=> IDEA使用常见问题记录 的2.1.3 uml图
在这里插入图片描述
14 Enum ChronoUnit  TemporalAmount 接口的实现类,采用枚举类的方式表示一些 计算常用时间单位。(常用 e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  例如: 一纳秒(ChronoUnit.NANOS
      一微秒(ChronoUnit.MICROS
      一毫秒(ChronoUnit.MILLIS
      一秒(ChronoUnit.SECONDS
      一分钟(ChronoUnit.MINUTES
     一小时(ChronoUnit.HOURS
     半天(ChronoUnit.HALF_DAYS
     一天(ChronoUnit.DAYS
     一周(ChronoUnit.WEEKS
     一个月(ChronoUnit.MONTHS
     一年(ChronoUnit.YEARS
     十年(ChronoUnit.DECADES
     百年(一个世纪)(ChronoUnit.CENTURIES
     千年(ChronoUnit.MILLENNIA
     十亿年(一个纪元)(ChronoUnit.ERAS
     2.92277266×1011年(永恒)(ChronoUnit.FOREVER
  实例: 获取举例今天100年以后的本地日期时间
      LocalDate DecadesFromNow = LocalDate.now().plus(1,ChronoUnit.DECADES);
--------------------------------------------------------------------------------------
  TemporalUnit是个接口,一般直接使用该接口在Java8自带的实现类即可(ChronoUnit)
  idea查看uml图方式=> IDEA使用常见问题记录 的2.1.3 uml图
在这里插入图片描述

2.3 时间其他类【按API功能类型分】

id类名作用
15ZoneOffset  表示与格林威治/ UTC的时区偏移量,如+02:00。时区偏移是时区与格林威治/ UTC不同的时间段。 这通常是固定的几小时和几分钟。(常用 a.日期向上转型:构建OffsetDateTime对象时,指定偏移)
  世界不同的地区有不同的时区偏移。 在ZoneId课程中会捕获偏移量随地点和年份变化的规则。
  例如,巴黎在冬季比格林威治/ UTC提前了一个小时,夏天还有两个小时。 该ZoneId实例巴黎将两个参考ZoneOffset实例-一个+01:00冬季实例,以及+02:00夏季实例。
16ZoneId  表示时区信息,通过 ZoneId.getAvailableZoneIds() 可以获取所有时区(常用 a.日期向上转型:构建ZonedDateTime对象时,指定时区)
  按字典序:
Africa/Abidjan Africa/Accra Africa/Addis_Ababa …【部分省略】… America/New_York America/Nipigon America/Nome America/Noronha America/North_Dakota/Beulah …【部分省略】… Asia/Shanghai Asia/Singapore Asia/Srednekolymsk Asia/Taipei Asia/Tashkent Asia/Tbilisi Asia/Tehran Asia/Tel_Aviv Asia/Thimbu Asia/Thimphu Asia/Tokyo Asia/Tomsk Asia/Ujung_Pandang Asia/Ulaanbaatar Asia/Ulan_Bator Asia/Urumqi …【部分省略】… WET Zulu
17 Enum TextStyle  采用枚举类的方式表示 文本格式和解析的风格。(常用 k. 枚举类 DayOfWeek:作为DayOfWeek.getDisplayName方法的参数,指定星期几的文本格式-长短)
  三种尺寸: (文本格式)
   “”(TextStyle.FULL)
   “”(TextStyle.SHORT
   “”(TextStyle.NARROW
  两种变体:(每种尺寸都有两种变体)
   “标准”(TextStyle.FULL
   “独立”(TextStyle.FULL_STANDALONE
  在大多数语言中,三种尺寸之间的差异是显而易见的。 例如,在英语中,“满月”为“一月”,“短”月为“一月”,“窄”月为“J”。 请注意,狭窄的大小通常不是唯一的。 例如,‘1月’,‘6月’和’7’都有’窄’文本’J’。
  “标准”和“独立”形式之间的区别是形容词难度很大,英文没有差别。 然而,在其他语言中,单独使用文本时使用的单词有所不同,而不是完整的日期。
  例如,一个月在单独使用日期选择器中使用的单词与用于与日期中的日期和年份相关联的月份的单词不同。
18Locale  Locale对象代表具体的地理,政治或文化地区。(常用 k. 枚举类 DayOfWeek:作为DayOfWeek.getDisplayName方法的参数,指定星期几的文本格式-地区)
  例如: 中国地区(Locale.CHINESE
19TemporalAdjusters
调节器
  类中所有方法都会返回一个 TemporalAdjuster 对象。
  表示一些 常用时间节点,供时间计算(g1. with + 调节器)。
  例如: 上一个星期几(TemporalAdjusters.previous(DayOfWeek dayOfWeek)
      上一个星期几或当天(TemporalAdjusters.previousOrSame(DayOfWeek dayOfWeek)
      下一个星期几(TemporalAdjusters.next(DayOfWeek dayOfWeek)
      下一个星期几或当天(TemporalAdjusters.nextOrSame(DayOfWeek dayOfWeek)
      当月第1天(TemporalAdjusters.firstDayOfMonth()
      当月最后1天(TemporalAdjusters.lastDayOfMonth()()
      当月第1个星期几(TemporalAdjusters.firstInMonth(DayOfWeek dayOfWeek)
      当月第n个星期几(TemporalAdjusters.dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)
      当月最后一个星期几(TemporalAdjusters.lastInMonth(DayOfWeek dayOfWeek)
      当年最后1天(TemporalAdjusters.lastDayOfYear()
      明年的第1天(TemporalAdjusters.firstDayOfNextYear()
      下月第1天(TemporalAdjusters.firstDayOfNextMonth()
      lambda表达式自定义指定日期(TemporalAdjusters.
                ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster)
  实例: 获取举例今天100年以后的日期
      LocalDate DecadesFromNow = LocalDate.now().plus(1,ChronoUnit.DECADES);
--------------------------------------------------------------------------------------
  Class TemporalAdjusters 并不是 interface TemporalAdjuster 的实现类,只不过 Class TemporalAdjusters 的静态方法实现了 interface TemporalAdjuster,并返回 interface TemporalAdjuster 对象的实例
20 Interface TemporalQuery  这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。
--------------------------------------------------------------------------------------
  在 c. 实例化对象 from 有使用的案例
21DateTimeFormatter  日期格式化器,用于打印和解析日期时间对象。(常用 i. 日期解析 format(日期->String):作为*.with的参数,按照一些特殊规则计算时间)
  常用方法:
    DateTimeFormatter.ofLocalizedDate 静态方法,自动识别时区的方式解析,需要传入一个FormatStyle的枚举值
    DateTimeFormatter.ofPattern 静态方法,指定日期格式的解析,需要传入一个字符串日期格式
  实例:
    String format1 = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE);
    String format2 = LocalDateTime.now().format(DateTimeFormatter.ofPattern(“yyyy-MM-dd’T’HH:mm:ss.SSS”));
--------------------------------------------------------------------------------------
  DateTimeFormatter预制的格式化器,最常用的两个:
  1. yyyy-MM-dd
    DateTimeFormatter.ISO_DATE
      => 2022-01-18
  2. yyyy-MM-dd’T’HH:mm:ss.SSS
    DateTimeFormatter.ISO_DATE_TIME
      =>2022-01-18T18:12:51.639
--------------------------------------------------------------------------------------
  带不带 LOCAL 的对比: 仅对 OffsetDateTime、ZonedDateTime 有区别
  1. LocalDateTime + ISO_DATE_TIME
    LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639
  2. LocalDateTime + ISO_LOCAL_DATE_TIME
    LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T18:12:51.639
  3. OffsetDateTime + ISO_DATE_TIME
    OffsetDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639+08:00
  4. OffsetDateTime + ISO_LOCAL_DATE_TIME
    OffsetDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T11:12:51.639
  5. ZonedDateTime + ISO_DATE_TIME
    ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
  6. ZonedDateTime + ISO_LOCAL_DATE_TIME
    ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T18:12:51.639
22 Enum FormatStyle  枚举本地化日期,时间或日期时间格式化的风格。(常用 i. 日期解析 format(日期->String):作为 DateTimeFormatter.ofLocalizedDate(FormatStyle dateStyle) 静态方法的参数使用,并返回一个 DateTimeFormatter 对象)
  例如: 全文格式(FormatStyle.FULL)=> 2022年1月18日 星期二
      长文本格式(FormatStyle.LONG)=> 2022年1月18日
      中等格式(FormatStyle.MEDIUM)=> 2022-1-18
      短文格式(FormatStyle.SHORT)=> 22-1-18
  实例: 全文格式解析本地日期时间
  String format =
     LocalDateTime.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
--------------------------------------------------------------------------------------
  需要注意 这种方式在不同时区的显示内容不一样,在其他时区不会显示中文
23 Interface TemporalField
时间结界
  日期时间的字段,如月份或小时。日期和时间使用将时间线划分成对人有意义的东西的字段来表示。 此接口的实现表示这些字段。最常用的单位在 ChronoField 中定义。(常用 i. g2. with + ChronoField
  血缘关系:
在这里插入图片描述
24 Enum ChronoField
时间结界
  “先(按不同规则)获取一个新的时间,再这个时间的基础上再调整时间”。
  表示一些 常用时间计算方式,供时间计算(g2. with + 时间结界)、时间获取(b13. get方法向下转型)。
  例如:纳秒(在秒中)(ChronoField.NANO_OF_SECOND取值范围[0, 999999999]
      纳秒(在天中)(ChronoField.NANO_OF_DAY取值范围[0, 86399999999999],需要使用getLong方法
      微秒(在秒中)(ChronoField.MICRO_OF_SECOND取值范围[0, 999999]
      微秒(在天中)(ChronoField.MICRO_OF_DAY取值范围[0, 86399999999],需要使用getLong方法
      毫秒(在秒中) (ChronoField.MILLI_OF_SECOND取值范围[0, 999]
      毫秒(在天中) (ChronoField.MILLI_OF_DAY取值范围[0, 86399999]
      秒(在分中)(ChronoField.SECOND_OF_MINUTE取值范围[0, 59]
      秒(在天中)(ChronoField.SECOND_OF_DAY取值范围[0, 86399]
      秒(从UTC/格林威治的偏移秒数)(ChronoField.OFFSET_SECONDS取值范围[-64800, 64800]
      注意:对象必须是包含时区信息的(OffsetDateTime、ZonedDateTime)
      举例:long offsetSecond = ZonedDateTime.of(ldt, ZoneId.of(“Asia/Shanghai”)).getLong(ChronoField.OFFSET_SECONDS); => 获取中国时区偏移秒数"29143"≈ 8.059小时,即东八区
      秒(Unix 时间戳1)(ChronoField.INSTANT_SECONDS取值范围[ Long.MIN_VALUE, Long.MAX_VALUE ],需要使用getLong方法,其中:
        LONG.MIN_VALUE = 0x8000000000000000L = - 264
        LONG.MAX_VALUE = 0x7fffffffffffffffL = 264 - 1
      注意:对象必须是包含时区信息的(OffsetDateTime、ZonedDateTime)

     分钟(在天中)(ChronoField.MINUTE_OF_DAY取值范围[0, 1439]
     分钟(在小时中)(ChronoField.MINUTE_OF_HOUR取值范围[0, 59]
     12小时制(用0代表当天0:00AM或0:00PM)(ChronoField.HOUR_OF_AMPM取值范围[0, 11]
     12小时制(用12代表当天0:00AM或0:00PM)(ChronoField.CLOCK_HOUR_OF_AMPM取值范围[1, 12]
       2022-02-01T01:00.with(ChronoField.CLOCK_HOUR_OF_AMPM, 5) => 2022-02-01T05:00(当天AM5:00,因为01:00属于上午)
       2022-02-01T14:00.with(ChronoField.CLOCK_HOUR_OF_AMPM, 5) => 2022-02-01T17:00(当天PM5:00,因为14:00属于下午)
     24小时制(用0代表当天0点) (ChronoField.HOUR_OF_DAY取值范围[0, 23]
     24小时制(用24代表当天0点)(ChronoField.CLOCK_HOUR_OF_DAY取值范围[1, 24]
     半天(AM=0,PM=1)(ChronoField.AMPM_OF_DAY取值范围[0,1]
     日(在周中)(ChronoField.DAY_OF_WEEK取值范围[1,7]
     日(在月中)(ChronoField.DAY_OF_MONTH取值范围[1,x],其中x∈[28,31] ,取决于当月有几天
     日(在年中)(ChronoField.DAY_OF_YEAR取值范围[1,x],其中x∈[365,366] ,取决于当年有几天
     日(自纪元时间2起)(ChronoField.EPOCH_DAY取值范围[(Year.MIN_VALUE * 365.25), (Year.MAX_VALUE * 365.25)],需要使用getLong方法,其中:
       Year.MIN_VALUE = -999999999;  => 最小值 Year.MIN_VALUE * 365.25 = -365249999634
       Year.MAX_VALUE = 999999999; => 最大值 Year.MAX_VALUE * 365.25 = 365249999634
     周几(月对齐3)(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH取值范围[1, 7]
     周几(年对齐4)(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR取值范围[1, 7]
     第几周(月对齐)(ChronoField.ALIGNED_WEEK_OF_MONTH取值范围[1, 5],其中x∈[4,5] ,取决于当月有几周(实际测试平年2月x=5也可以)
     第几周(年对齐)(ChronoField.ALIGNED_WEEK_OF_YEAR取值范围[1, 53]
     月(在年中)(ChronoField.MONTH_OF_YEAR取值范围[1, 12]
     月(自公元5“0000年1月"起)(ChronoField.PROLEPTIC_MONTH取值范围[Year.MIN_VALUE * 12L, Year.MAX_VALUE * 12L + 11],需要使用getLong方法,其中:
       Year.MIN_VALUE = -999999999; => 最小值 Year.MIN_VALUE * 12L = 11999999988
       Year.MAX_VALUE = 999999999; => 最大值 Year.MAX_VALUE * 12L + 11 = 11999999999

     年(ChronoField.YEAR取值范围[ Year.MIN_VALUE, Year.MAX_VALUE],需要使用getLong方法,其中:
       Year.MIN_VALUE = -999999999; => 最小值
       Year.MAX_VALUE = 999999999; => 最大值
     年(自公元1年起)(ChronoField.YEAR_OF_ERA取值范围需要分类讨论,需要使用getLong方法,其中:
       ① 0001-01-01T00:00之前的时间(包含此刻), 属于公元前,取值范围[ 1, Year.MAX_VALUE + 1 ] => [ 1, 1000000000 ]
       ② 0001-01-01T00:00之后的时间(不包含此刻),属于公元前,取值范围[ 1, Year.MAX_VALUE ] => [ 1, 999999999 ]
       其原因是:公元后开始于1年1月1日0点,所以 年份∈ [ -999999999 ,0 ] 时,是公元前。年份∈ [ 1, 999999999 ] 时,是公元后。就时间范围来说,公元前比公元后要多1年。

     时代(公元前=0,公元后=1)(ChronoField.ERA取值范围[0, 1],举例(伪代码):
       2022-02-01T00:00.with(ChronoField.EPOCH_DAY, 0) => -2022-02-01T00:00(变为负值)
       2022-02-01T00:00.with(ChronoField.EPOCH_DAY, 1) => 2022-02-01T00:00(不变)
  举例(伪代码): 2022-01-01T02:03:04 在这一天内过了几分钟?
      “2022-01-01T02:03:04”.get(ChronoField.MINUTE_OF_DAY); => 123
--------------------------------------------------------------------------------------
  19.TemporalAdjusters 调节器 和 24.ChronoField 时间结界 都可以作为with参数修改时间(当然这2个的中文名字都是我自己编的,网上资料实在太少),区别在于:
  TemporalAdjusters 的修改日期是 基于当前时间 的,规则较为简单(例如上个星期一当月第1个星期五明年第5天等)。
  ChronoField 的修改时间是 基于一个新的时间 ,规则较为复杂的(例如 ChronoField.SECOND_OF_DAY先根据当前时间获取所在天,舍弃小时、分的信息,再基于这个时间设置一个新的秒数
      => 秒(在天中)(ChronoField.SECOND_OF_DAY取值范围[0, 86399],下面是一行伪代码,便于理解什么是"基于一个新的时间”
      => 2022-01-01T02:03:04.000056789.with(ChronoField.SECOND_OF_DAY, 8) => 2022-01-01T00:00:08.000056789
  2022-01-01T02:03:04.000056789 => 先获取所在天的信息 => 2022-01-01T00:00:00.000056789 (小于秒的信息还保留着)
  2022-01-01T00:00:00.000056789 => 对其赋值 SECOND=8 => 2022-01-01T00:00:08.000056789

14. ZoneOffset 的使用案例

		//获取当前时区偏移+5小时时间
		ZonedDateTime zdt = ZonedDateTime.ofInstant(LocalDateTime.now(), 
													ZoneOffset.of("+05:00"), 
													ZoneId.systemDefault());

15. ZoneId 的使用案例

        //获取所有的时区信息
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        //availableZoneIds.forEach(System.out::println);//...
	
        //获取当前系统默认的时区信息 -> 中国
        ZoneId zoneId = ZoneId.systemDefault();
        System.out.println(zoneId);//Asia/Shanghai

17. TextStyle & 18. Locale 的使用案例

        String monday = DayOfWeek.of(1).getDisplayName(TextStyle.FULL, Locale.CHINESE);
        System.out.println(monday);//星期一

19. TemporalAdjusters 的使用案例

  更多详情查看 g1. with + 调节器

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        //可以作为 -> with 方法的参数调节日期,例如:获取"下个星期五"的日期
        TemporalAdjuster previous = TemporalAdjusters.next(DayOfWeek.of(5));
        LocalDateTime nextFriday = ldt.with(previous);
        //2022-01-01T00:00是星期六,他的下一个周五日期是2022-01-07T00:00
        System.out.println(ldt + "是" + ldt.getDayOfWeek().
                getDisplayName(TextStyle.FULL, Locale.CHINESE) +
                                   ",他的下一个周五日期是" + nextFriday);
    }

20. TemporalQuery 的使用案例

  更多详情查看 h. 日期查询 query

    public static void main(String[] args) {
        //创建日期对象2022年5月31日,模拟计算
        LocalDate today = LocalDate.of(2022, 5, 31);
        HashMap<String, Long> queryResult = today.query(new TemporalQuery<HashMap<String, Long>>() {
            @Override
            public HashMap<String, Long> queryFrom(TemporalAccessor temporalAccessor) {
                //1.将 temporalAccessor 转为LocalDate对象
                LocalDate ld = LocalDate.from(temporalAccessor);
                //2.创建容器
                HashMap<String, LocalDate> ldMap = new HashMap<>();
                HashMap<String, Long> resultMap = new HashMap<>();
                //3.封装当年的圣诞节/儿童节/劳动节的时间对象
                ldMap.put("圣诞节", LocalDate.of(ld.getYear(), Month.DECEMBER, 2));
                ldMap.put("儿童节", LocalDate.of(ld.getYear(), Month.JUNE, 1));
                ldMap.put("劳动节", LocalDate.of(ld.getYear(), Month.MAY, 1));
                //4.判断date是否已经超过了d1/d2/d3三个节日,如果超过了,则计算下一年的日期
                for (String key : ldMap.keySet()) {
                    LocalDate holidayDate = ldMap.get(key);
                    //如果当前时间>当年节日,则节日日期+1年
                    if (ld.isAfter(holidayDate)) holidayDate = holidayDate.plusYears(1);
                    //计算:距离该节日还差几天
                    resultMap.put(key, ChronoUnit.DAYS.between(ld, holidayDate));
                }
                //5.返回结果
                return resultMap;
            }
        });
        //打印结果
        for (String holidayName : queryResult.keySet()) {
            //距离下一个儿童节还剩1天
            //距离下一个劳动节还剩335天
            //距离下一个圣诞节还剩185天
            System.out.println("距离下一个" + holidayName + "还剩" + queryResult.get(holidayName) + "天");
        }
    }

21. DateTimeFormatter 的使用案例

  更多详情查看 i. 日期解析 format

	public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.now();
        String format1 = ldt.format(DateTimeFormatter.ISO_DATE);
        String format2 = ldt.format(DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(format1);//2022-01-18
        System.out.println(format2);//2022-01-18T18:12:51.639
	}

22. FormatStyle 的使用案例

  更多详情查看 i2. 自动识别时区

	public static void main(String[] args) {
		LocalDateTime ldt = LocalDateTime.now();
		String fullTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
		String longTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
		String mediumTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
		String shortTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
		System.out.println(fullTime);//2022年1月18日 星期二
		System.out.println(longTime);//2022年1月18日
		System.out.println(mediumTime);//2022-1-18
		System.out.println(shortTime);//22-1-18
	}

23. TemporalField 的使用案例

  一般使用其实现类 24. ChronoField

24. ChronoField 的使用案例

  更多详情查看 5. 新API详解,id=24 ChronoField 时间结界


3. 新API实例 - 时间点类


a. 日期向上转型


+
LocalDateTime.of
LocalDate.atTime
LocalTime.atDate
+
LocalDateTime.ofInstant
OffsetDateTime.ofInstant
Instant.atOffset
ZonedDateTime.ofInstant
Instant.atZone
+
OffsetDateTime.of
LocalDateTime.atOffset
+
ZonedDateTime.of
LocalDateTime.atZone
+
ZonedDateTime.
ofInstant
ofStrict
ofLocal
15.ZoneId
时区信息
15.ZoneId
时区信息
14.ZoneOffset
时区偏移量
14.ZoneOffset
时区偏移量
1.Instant
时间戳
7.LocalTime
本地时间
8.LocalDate
本地日期
7.LocalTime
本地时间
9.LocalDateTime
本地日期时间
10.OffsetDateTime
偏移的日期时间
11.ZonedDateTime
带时区的日期时间
11.ZonedDateTime
带偏移+时区的日期时间

a1.Instant -> LocalDateTime

  为 Instant(格林威治时间戳) 添加 ZoneId(时区信息)即可得到 LocalDateTime (本地日期时间)。

  LocalDateTime.ofInstant(Instant instant, ZoneId zone) 静态方法

public static void main(String[] args) {
	//LocalDateTime ldt = LocalDateTime.ofInstant(Instant.now(), ZoneId.of("Asia/Shanghai"));
	LocalDateTime ldt = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
	System.out.println(ldt);//2022-01-18T18:12:51.639
}

a2.Instant -> OffsetDateTime

  为 Instant(格林威治时间戳) 添加 ZoneId(时区信息)即可得到 OffsetDateTime (偏移的日期时间)。

  OffsetDateTime.ofInstant(Instant instant, ZoneId zone) 静态方法
  Instant.atOffset(ZoneOffset offset) 方法

public static void main(String[] args) {
	Instant now = Instant.now();
	//OffsetDateTime.ofInstant 静态方法
	OffsetDateTime odt1 = OffsetDateTime.ofInstant(now, ZoneId.systemDefault());
	System.out.println(odt1);//2022-01-18T18:12:51.639+08:00
	//Instant.atOffset 方法
	OffsetDateTime odt2 = now.atOffset(ZoneOffset.of("+01:00"));
	System.out.println(odt2);//2022-01-18T11:12:51.639+00:00
	OffsetDateTime odt3 = now.atOffset(ZoneOffset.of("+00:00"));
	System.out.println(odt3);//2022-01-18T10:12:51Z
}

a3.Instant -> ZonedDateTime

  为 Instant(格林威治时间戳) 添加 ZoneId(时区信息)即可得到 ZonedDateTime (具有时区的日期时间)。

  ZonedDateTime.ofInstant(Instant instant, ZoneId zone) 静态方法
  Instant.atZone(ZoneId zone) 方法

public static void main(String[] args) {
	Instant now = Instant.now();
	ZonedDateTime zdt1 = ZonedDateTime.ofInstant(now, ZoneId.systemDefault());
	System.out.println(zdt1);//2022-01-18T12:51.639+08:00[Asia/Shanghai]
	ZonedDateTime zdt2 = now.atZone(ZoneId.systemDefault());
	System.out.println(zdt2);//2022-01-18T12:51.639+08:00[Asia/Shanghai]
}

a4.LocalDate -> LocalDateTime

  为 LocalDate(本地日期)指定默认时间 LocalTime.MIDNIGHT(本地时间的00:00)即可得到 LocalDateTime (本地日期时间)。

  LocalDate.atStartOfDay() 方法 会丢失小时级时间精度

public static void main(String[] args) {
	LocalDate ld = LocalDate.now();
	LocalDateTime ldt = ld.atStartOfDay();
	System.out.println(ldt);//2022-01-18T00:00
}

a5.LocalDate + LocalTime -> LocalDateTime

  为 LocalDate(本地日期)添加 LocalTime(本地时间)即可得到 LocalDateTime (本地日期时间)。

  LocalDateTime.of(LocalDate date, LocalTime time) 静态方法
  LocalTime.atDate(LocalDate date) 方法
  LocalDate.atTime(LocalTime time) 方法

public static void main(String[] args) {
	LocalDate ld = LocalDate.now();
	LocalTime lt = LocalTime.now();
	
	//LocalDateTime.of(LocalDate date, LocalTime time) 静态方法
	LocalDateTime ldt1 = LocalDateTime.of(ld, lt);
	System.out.println(ldt1);//2022-01-18T16:37
	
	//LocalTime.atDate(LocalDate date) 方法
	LocalDateTime ldt2 = lt.atDate(ld);
	System.out.println(ldt2);//2022-01-18T16:37
	
	//LocalDate.atTime(LocalTime time) 方法
	LocalDateTime ldt3 = ld.atTime(lt);
	System.out.println(ldt3);//2022-01-18T16:37
}

a6.LocalDate -> ZonedDateTime

  为 LocalDate(本地日期)添加 ZoneId(时区信息)即可得到 ZonedDateTime (具有时区的时间日期)。

  LocalDate.atStartOfDay(ZoneId zone) 静态方法 会丢失小时级时间精度

public static void main(String[] args) {
	LocalDate ld = LocalDate.now();
	ZonedDateTime zdt = ld.atStartOfDay(ZoneId.systemDefault());
	System.out.println(zdt);//2022-01-18T00:00+08:00[Asia/Shanghai]
}

a7.LocalDate + LocalTime -> LocalDateTime

  为 LocalDate(本地日期)添加 LocalTime(本地时间)即可得到 LocalDateTime (本地日期时间)。

  LocalDateTime.of(LocalDate date, LocalTime time) 静态方法

public static void main(String[] args) {
	LocalDateTime ldt = LocalDateTime.of(LocalDate.now(), LocalTime.now());
	System.out.println(ldt);//2022-01-18T16:37
}

a8.LocalDateTime -> OffsetDateTime

  为 LocalDateTime(本地日期时间) 添加 ZoneOffset(时区偏移量)即可得到 OffsetDateTime (偏移的日期时间)。

  OffsetDateTime.of(LocalDateTime dateTime, ZoneOffset offset) 静态方法
  LocalDateTime.atOffset(ZoneOffset offset) 方法

public static void main(String[] args) {
	LocalDateTime now = LocalDateTime.now();
	//OffsetDateTime.of 静态方法
	OffsetDateTime odt1 = OffsetDateTime.of(now, ZoneOffset.of("+08:00"));
	System.out.println(odt1);//2022-01-18T18:12:51.639+08:00
	//LocalDateTime.atOffset 方法
	OffsetDateTime odt2 = now.atOffset(ZoneOffset.of("+08:00"));
	System.out.println(odt2);//2022-01-18T18:12:51.639+08:00
}

a9.LocalDateTime -> ZonedDateTime

  为 LocalDateTime(本地日期时间) 添加 ZoneId(时区信息)即可得到 ZonedDateTime (具有时区的日期时间)。

  ZonedDateTime.of(LocalDateTime localDateTime, ZoneId zone) 静态方法
  LocalDateTime.atZone(ZoneId zone) 方法

public static void main(String[] args) {
	LocalDateTime now = LocalDateTime.now();
	//ZonedDateTime.of 静态方法
	ZonedDateTime zdt1 = ZonedDateTime.of(now, ZoneId.systemDefault());
	System.out.println(zdt1);//2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
	//LocalDateTime.atZone 方法
	ZonedDateTime zdt2 = now.atZone(ZoneId.systemDefault());
	System.out.println(zdt2);//2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
}

a10.LocalDateTime -> ZonedDateTime(区域偏移)

  为 LocalDateTime(本地日期时间)添加 ZoneId(时区信息)和 ZoneOffset(区域偏移)即可得到 ZonedDateTime (具有时区的日期时间)。共有三种方法实现,三种方法的具体区别不详

  ZonedDateTime.ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) 静态方法
  ZonedDateTime.ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) 静态方法
  ZonedDateTime.ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) 静态方法

//实例
public static void main(String[] args) {
        ZonedDateTime zdt1 = ZonedDateTime.ofInstant(LocalDateTime.of(2022,1,18,18,12,51),
                ZoneOffset.of("+06:00"),
                ZoneId.systemDefault());
        System.out.println(zdt1);//2022-01-18T20:12:51+08:00[Asia/Shanghai]

        ZonedDateTime zdt2 = ZonedDateTime.ofInstant(LocalDateTime.of(2022,1,18,18,12,51),
                ZoneOffset.of("+06:00"),
                ZoneId.systemDefault());
        System.out.println(zdt2);//2022-01-18T20:12:51+08:00[Asia/Shanghai]

        ZonedDateTime zdt3 = ZonedDateTime.ofLocal(LocalDateTime.of(2022,1,18,18,12,51),
                ZoneId.systemDefault(),
                ZoneOffset.of("+06:00"));
        System.out.println(zdt3);//2022-01-18T18:12:51+08:00[Asia/Shanghai]
}

a11.LocalDate + LocalTime -> OffsetDateTime

  a7(LocalDate + LocalTime -> LocalDateTime) 和 a8 (LocalDateTime -> OffsetDateTime)方法的变体。
  OffsetDateTime.of(LocalDate date, LocalTime time, ZoneId zone) 静态方法

public static void main(String[] args) {
	ZonedDateTime zdt = ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.systemDefault());
	System.out.println(zdt);//2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
}

a12.LocalDate + LocalTime -> ZonedDateTime

  a7(LocalDate + LocalTime -> LocalDateTime) 和 a9 (LocalDateTime -> ZonedDateTime)方法的变体。
  ZonedDateTime.of(LocalDate date, LocalTime time, ZoneId zone) 静态方法

public static void main(String[] args) {
	ZonedDateTime zdt = ZonedDateTime.of(LocalDate.now(), LocalTime.now(), ZoneId.systemDefault());
	System.out.println(zdt);//2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
}

b.日期向下转型

LocalDateTime.toInstant
LocalDateTime.toInstant
LocalDateTime.toInstant
OffsetDateTime.toInstant
OffsetDateTime.toLocalDate
OffsetDateTime.toLocalTime
OffsetDateTime.toLocalDateTime
ZonedDateTime.toInstant
ZonedDateTime.toLocalDate
ZonedDateTime.toLocalTime
ZonedDateTime.toLocalDateTime
ZonedDateTime.toOffsetDateTime
1.Instant
时间戳
7.LocalTime
本地时间
8.LocalDate
本地日期
9.LocalDateTime
本地日期时间
10.OffsetDateTime
偏移的日期时间
11.ZonedDateTime
带时区的日期时间

b1. LocalDateTime -> Instant

  LocalDateTime (本地日期时间)通过 LocalDateTime.toInstant()方法 获取 Instant(格林威治时间戳)

public static void main(String[] args) {
	LocalDateTime ldt = LocalDateTime.now();
	Instant instant = ldt.toInstant(ZoneOffset.UTC);
	System.out.println(instant);//2022-01-18T18:12:51.639Z
}

b2. LocalDateTime -> LocalTime

  LocalDateTime (本地日期时间)通过 LocalDateTime.toLocalTime()方法 获取 LocalTime(本地时间)

public static void main(String[] args) {
    LocalDateTime ldt = LocalDateTime.now();
    LocalTime lt = ldt.toLocalTime();
	System.out.println(lt);//18:12:51.639
}

b3. LocalDateTime -> LocalDate

  LocalDateTime (本地日期时间)通过 LocalDateTime.toLocalDate()方法 获取 LocalDate(本地日期)

public static void main(String[] args) {
    LocalDateTime ldt = LocalDateTime.now();
    LocalDate ld = ldt.toLocalDate();
	System.out.println(ld);//2022-01-18
}

b4. OffsetDateTime -> Instant

  OffsetDateTime (偏移的日期时间)通过 OffsetDateTime.toInstant()方法 获取 Instant(格林威治时间戳)

public static void main(String[] args) {
    OffsetDateTime odt = OffsetDateTime.now();
    Instant instant = odt.toInstant();
	System.out.println(instant);//2022-01-18T10:12:51Z
}

b5. OffsetDateTime -> LocalTime

  OffsetDateTime (偏移的日期时间)通过 OffsetDateTime.toLocalTime()方法 获取 LocalTime(本地时间)

public static void main(String[] args) {
    OffsetDateTime odt = OffsetDateTime.now();
    LocalTime lt = odt.toLocalTime();
	System.out.println(lt);//18:12:51.639
}

b6. OffsetDateTime -> LocalDate

  OffsetDateTime (偏移的日期时间)通过 OffsetDateTime.toLocalDate()方法 获取 LocalDate(本地日期)

public static void main(String[] args) {
    OffsetDateTime odt = OffsetDateTime.now();
    LocalDate ld = odt.toLocalDate();
	System.out.println(ld);//2022-01-18
}

b7. OffsetDateTime -> LocalDateTime

  OffsetDateTime (偏移的日期时间)通过 OffsetDateTime.toLocalDateTime()方法 获取 LocalDateTime(本地日期时间)

public static void main(String[] args) {
    OffsetDateTime odt = OffsetDateTime.now();
    LocalDateTime ldt = odt.toLocalDateTime();
	System.out.println(ldt);//2022-01-18T18:12:51.639
}

b8. ZonedDateTime -> Instant

  ZonedDateTime (具有时区的日期时间)通过 ZonedDateTime.toInstant()方法 获取 Instant(格林威治时间戳)

public static void main(String[] args) {
    ZonedDateTime zdt = ZonedDateTime.now();
    Instant instant = zdt.toInstant();
	System.out.println(instant);//2022-01-18T10:12:51Z
}

b9. ZonedDateTime -> LocalTime

  ZonedDateTime (具有时区的日期时间)通过 ZonedDateTime.toLocalTime()方法 获取 LocalTime(本地时间)

public static void main(String[] args) {
    ZonedDateTime zdt = ZonedDateTime.now();
    LocalTime lt = zdt.toLocalTime();
	System.out.println(lt);//18:12:51.639
}

b10. ZonedDateTime -> LocalDate

  ZonedDateTime (具有时区的日期时间)通过 ZonedDateTime.toLocalDate()方法 获取 LocalDate(本地日期)

public static void main(String[] args) {
    ZonedDateTime zdt = ZonedDateTime.now();
    LocalDate ld = zdt.toLocalDate();
	System.out.println(ld);//2022-01-18
}

b11. ZonedDateTime -> LocalDateTime

  ZonedDateTime (具有时区的日期时间)通过 ZonedDateTime.toLocalDateTime()方法 获取 LocalDate(本地日期时间)

public static void main(String[] args) {
    ZonedDateTime zdt = ZonedDateTime.now();
    LocalDateTime ldt = zdt.toLocalDateTime();
	System.out.println(ldt);//2022-01-18T18:12:51.639
}

b12. ZonedDateTime -> OffsetDateTime

  ZonedDateTime (具有时区的日期时间)通过 ZonedDateTime.toOffsetDateTime()方法 获取 OffsetDateTime(偏移的日期时间)

public static void main(String[] args) {
    ZonedDateTime zdt = ZonedDateTime.now();
    OffsetDateTime odt = zdt.toOffsetDateTime();
	System.out.println(odt);//2022-01-18T18:12:51.639+08:00
}

b13. get方法向下转型

  见 => 5. 新API详解 ,id=24 ChronoField 时间结界


c. 实例化对象 from

  在使用 h.日期查询 query 方法时,需要实现 Temporaquery 接口的 queryFrom 方法,这个方法入参是一个 TemporalAccessor 对象。通过静态方法 from() 可以将其转为对应的时间对象。

    public static void main(String[] args) {
        LocalDateTime.now().query(new TemporalQuery<Object>() {
            @Override
            public Object queryFrom(TemporalAccessor ta) {
                Instant i = Instant.from(ta);
                LocalDate ld = LocalDate.from(ta);
                LocalTime lt = LocalTime.from(ta);
                LocalDateTime ldt = LocalDateTime.from(ta);
                OffsetDateTime odt = OffsetDateTime.from(ta);
                ZonedDateTime zdt = ZonedDateTime.from(ta);
                return 0;
            }
        });
    }

d. 获取当前时间 now


d1. Instant.now(2种)

d1. Instant
  Instant.now( ):从 系统时间 获取 Instant(格林威治时间戳) 。

    public static void main(String[] args) {
        //instant无参构造:2022-01-18T10:12:51.639Z
        Instant i = Instant.now();
        System.out.println("instant无参构造:" + i);
    }

d2. LocalTime.now(2种)

d2. LocalTime
  Instant.now( )       :从 默认时区 系统时间 获取 LocalTime(本地时间)。
  Instant.now(ZoneId zone) :从 指定时区 系统时间 获取 LocalTime(本地时间)。

    public static void main(String[] args) {
        //LocalTime默认时区:18:12:51.639
        //LocalTime指定时区:18:12:51.639
        LocalTime lt1 = LocalTime.now();
        LocalTime lt2 = LocalTime.now(ZoneId.systemDefault());
        System.out.println("LocalTime默认时区:" + lt1);
        System.out.println("LocalTime指定时区:" + lt2);
    }

d3. LocalDate.now(2种)

d3. LocalDate
  LocalDate.now( )       :从 默认时区 系统时间 获取 LocalDate(本地日期)。
  LocalDate.now(ZoneId zone) :从 指定时区 系统时间 获取 LocalDate(本地日期)。

    public static void main(String[] args) {
        //LocalDate默认时区:2022-01-18
        //LocalDate指定时区:2022-01-18
        LocalDate ld1 = LocalDate.now();
        LocalDate ld2 = LocalDate.now(ZoneId.systemDefault());
        System.out.println("LocalDate默认时区:" + ld1);
        System.out.println("LocalDate指定时区:" + ld2);
    }

d4. LocalDateTime.now(2种)

d4. LocalDateTime.now()
  LocalDateTime.now( )       :从 默认时区 系统时间 获取 LocalDateTime(本地日期时间)。
  LocalDateTime.now(ZoneId zone) :从 指定时区 系统时间 获取 LocalDateTime(本地日期时间)。

    public static void main(String[] args) {
        //LocalDateTime默认时区:2022-01-18T18:12:51.639
        //LocalDateTime指定时区:2022-01-18T18:12:51.639
        LocalDateTime ldt1 = LocalDateTime.now();
        LocalDateTime ldt2 = LocalDateTime.now(ZoneId.systemDefault());
        System.out.println("LocalDateTime默认时区:" + ldt1);
        System.out.println("LocalDateTime指定时区:" + ldt2);
    }

d5. OffsetDateTime.now(2种)

d5. OffsetDateTime
  OffsetDateTime.now( )       :从 默认时区 系统时间 获取 OffsetDateTime(偏移的日期时间)。
  OffsetDateTime.now(ZoneId zone) :从 指定时区 系统时间 获取 OffsetDateTime(偏移的日期时间)。

    public static void main(String[] args) {
        //OffsetDateTime默认时区::2022-01-18T18:12:51.639
        //OffsetDateTime指定时区:2022-01-18T18:12:51.639
        OffsetDateTime odt1 = OffsetDateTime. now();
        OffsetDateTime odt2 = OffsetDateTime.now(ZoneId.systemDefault());
        System.out.println("OffsetDateTime:" + odt1);
        System.out.println("OffsetDateTime:" + odt2);
    }

d6. ZonedDateTime.now(2种)

d6. ZonedDateTime
  ZonedDateTime.now( )       :从 默认时区 系统时间 获取 OffsetDateTime(偏移的日期时间)。
  ZonedDateTime.now(ZoneId zone) :从 指定时区 系统时间 获取 OffsetDateTime(偏移的日期时间)。

    public static void main(String[] args) {
        //ZonedDateTime默认时区::2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
        //ZonedDateTime指定时区:2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
        ZonedDateTime zdt1 = ZonedDateTime.now();
        ZonedDateTime zdt2 = ZonedDateTime.now(ZoneId.systemDefault());
        System.out.println("ZonedDateTime:" + zdt1);
        System.out.println("ZonedDateTime:" + zdt2);
    }

e. 日期加法 plus(减法 minus )


e1.时间戳增减

e1.时间戳增减: Instant中可使用。
  1. plusNanos(long nanos)  :增加 纳秒 (对应减少纳秒minusNanos,后面省略不写)
  2. plusMillis(long seconds) :增加 毫秒
  3. Seconds(long minutes)   :增加

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 18, 18, 12, 51, 639000000);
        //原始时间:2022-01-18T10:12:51.639Z
        Instant i = ldt.atZone(ZoneId.systemDefault()).toInstant();//Instant i = ldt.toInstant(ZoneOffset.of("+08:00"));
        System.out.println("原始时间:" + i);
        
        //1纳秒后时间:2022-01-18T10:12:51.639000001Z
        Instant i1 = i.plusNanos(1);
        System.out.println("1纳秒后时间:" + i1);

        //2毫秒后时间:2022-01-18T10:12:51.641Z
        Instant i2 = i.plusMillis(2);
        System.out.println("2毫秒后时间:" + i2);

        //3秒后时间:2022-01-18T10:12:54.639Z
        Instant i3 = i.plusSeconds(3);
        System.out.println("3秒后时间:" + i3);
    }

e2.时间增减

e2.时间增减: LocalTime、LocalDateTime、OffSetDateTime、ZonedDateTime中均可使用。
  1. plusNanos(long nanos)   :增加 纳秒 (减少纳秒minusNanos,后面涉及到各plus方法均有对应minus方法)
  2. plusSeconds(long seconds) :增加
  3. plusMinutes(long minutes)   :增加 分钟
  4. plusHours(long hours)     :增加 小时

    public static void main(String[] args) {
        //原始时间:2022-01-18T18:12:51.639
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 18, 18, 12, 51, 639000000);
        //原始时间:18:12:51.639
        LocalTime lt = ldt.toLocalTime();
        System.out.println("原始时间:" + lt);

        //1纳秒后时间:18:12:51.639000001
        LocalTime lt1 = lt.plusNanos(1);
        System.out.println("1纳秒后时间:" + lt1);

        //2秒后时间:18:12:53.639
        LocalTime lt2 = lt.plusSeconds(2);
        System.out.println("2秒后时间:" + lt2);

        //3分钟后时间:18:15:51.639
        LocalTime lt3 = lt.plusMinutes(3);
        System.out.println("3分钟后时间:" + lt3);

        //4小时后时间:22:12:51.639
        LocalTime lt4 = lt.plusHours(4);
        System.out.println("4小时后时间:" + lt4);
    }

e3.日期增减

e3.日期增减: LocalDate、LocalDateTime、OffSetDateTime、ZonedDateTime中均可使用。
  1. plusDays(long days)     :增加 天数 (减少天数minusDays,后面涉及到各plus方法均有对应minus方法)
  2. plusWeeks(long weeks)  :增加
  3. plusMonths(long months)  :增加
  4. plusYears(long years)   :增加

    public static void main(String[] args) {
        //原始时间:2022-01-18T18:12:51.639
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 18, 18, 12, 51, 639000000);
        System.out.println("原始时间:" + ldt);

        //1天后时间:2022-01-19T18:12:51.639
        LocalDateTime ldt1 = ldt.plusDays(1);
        System.out.println("1天后时间:" + ldt1);

        //2周后时间:2022-02-01T18:12:51.639
        LocalDateTime ldt2 = ldt.plusWeeks(2);
        System.out.println("2周后时间:" + ldt2);

        //3月后时间:2022-04-18T18:12:51.639
        LocalDateTime ldt3 = ldt.plusMonths(3);
        System.out.println("3月后时间:" + ldt3);

        //4年后时间:2026-01-18T18:12:51.639
        LocalDateTime ldt4 = ldt.plusYears(4);
        System.out.println("4年后时间:" + ldt4);
    }

e4.范围增减(Duration or Period)

e4.范围增减: plus(TemporalAmount amount) 增加一个 时间范围,例如2年3个月4小时,参数(TemporalAmount amount) 是个接口,一般直接使用其实现类 Duration 和 Period,特殊规则可以自定义一个实现类

id类名作用
12Duration  TemporalAmount 接口的实现类,表示秒或纳秒时间间隔,适合处理需要时间高精确性的场景(秒杀)。(常用 l. 时间间隔 between:作为Duration.between静态方法的参数。)
13Period  TemporalAmount 接口的实现类,表示一段时间(年、月、日)。(常用 l. 时间间隔 between:作为Duration.between静态方法的参数。e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  实例: 获取距离今天1年2个月零3天以后的本地日期时间
      LocalDateTime result = LocalDateTime.now().plus(Period.of(1, 2, 3));
--------------------------------------------------------------------------------------
  TemporalUnit是个接口,一般直接使用该接口在Java8自带的实现类即可(Duration、Period)
  idea查看uml图方式=> IDEA使用常见问题记录 的2.1.3 uml图
在这里插入图片描述
12.Duration

k1. Duration.of(数量,单位)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration1 = Duration.of(1, ChronoUnit.NANOS);//一纳秒
        /*
        Duration duration2 = Duration.of(1, ChronoUnit.MICROS);//一微秒
        Duration duration3 = Duration.of(1, ChronoUnit.MILLIS);//一毫秒
        Duration duration4 = Duration.of(1, ChronoUnit.SECONDS);//一秒
        Duration duration5 = Duration.of(1, ChronoUnit.MINUTES);//一分钟
        Duration duration6 = Duration.of(1, ChronoUnit.HOURS);//一小时
        Duration duration7 = Duration.of(1, ChronoUnit.HALF_DAYS);//半天
        Duration duration8 = Duration.of(1, ChronoUnit.DAYS);//一天
        */
        try {
            Duration duration9 = Duration.of(1, ChronoUnit.WEEKS);//一周
            /*
            Duration duration10 = Duration.of(1, ChronoUnit.MONTHS);//一月
            Duration duration11 = Duration.of(1, ChronoUnit.YEARS);//一年
            Duration duration12 = Duration.of(1, ChronoUnit.DECADES);//十年
            Duration duration13 = Duration.of(1, ChronoUnit.CENTURIES);//百年(一个世纪)
            Duration duration14 = Duration.of(1, ChronoUnit.MILLENNIA);//千年
            Duration duration15 = Duration.of(1, ChronoUnit.ERAS);//十亿年(一个纪元)
            Duration duration16 = Duration.of(1, ChronoUnit.FOREVER);//2.92277266×1011年(永恒)
         	*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        LocalDateTime plus = ldt.plus(duration1);
		System.out.println(ldt + " =>" + plus);
    }

k2. Duration.ofNanos(纳秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofNanos(1);
        //2022-01-01T00:00 => 2022-01-01T00:00:00.000000001
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k3. Duration.ofMillils(毫秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofMillis(2);
        //2022-01-01T00:00 => 2022-01-01T00:00:00.002
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k4. Duration.ofSeconds(秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofSeconds(3);
        //2022-01-01T00:00 => 2022-01-01T00:00:03
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k5. Duration.ofSeconds(秒,纳秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofSeconds(4,5);
        //2022-01-01T00:00 => 2022-01-01T00:00:04.000000005
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k6. Duration.ofMinutes(分钟)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofMinutes(6);
        //2022-01-01T00:00 => 2022-01-01T00:06
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k7. Duration.ofHours(小时)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofHours(7);
        //2022-01-01T00:00 => 2022-01-01T07:00
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k8. Duration.ofDays(天)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofDays(8);
        //2022-01-01T00:00 => 2022-01-09T00:00
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }
13.Period

k9. Period.of(年,月,日)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.of(1, 2, 3);
        //2022-01-01T00:00 => 2023-03-04T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k10. Period.ofDays(日)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofDays(4);
        //2022-01-01T00:00 => 2022-01-05T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k11. Period.ofWeeks(周)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofWeeks(5);
        //2022-01-01T00:00 => 2022-02-05T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k12. Period.ofMonths(月)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofWeeks(5);
        //2022-01-01T00:00 => 2022-07-01T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k13. Period.ofYears(年)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofYears(7);
        //2022-01-01T00:00 => 2029-01-01T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

e5.时间单位增减(ChronoUnit )

e5. 时间单位增减: plus(long amountToAdd, TemporalUnit unit) 指定最小单位、最小单位个数;
        例如: 增加5个世纪 => plus(5,ChronoUnit.CENTURIES)

id类名作用
14 Enum ChronoUnit  TemporalAmount 接口的实现类,采用枚举类的方式表示一些 计算常用时间单位。(常用 e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  例如: 一纳秒(ChronoUnit.NANOS
      一微秒(ChronoUnit.MICROS
      一毫秒(ChronoUnit.MILLIS
      一秒(ChronoUnit.SECONDS
      一分钟(ChronoUnit.MINUTES
     一小时(ChronoUnit.HOURS
     半天(ChronoUnit.HALF_DAYS
     一天(ChronoUnit.DAYS
     一周(ChronoUnit.WEEKS
     一个月(ChronoUnit.MONTHS
     一年(ChronoUnit.YEARS
     十年(ChronoUnit.DECADES
     百年(一个世纪)(ChronoUnit.CENTURIES
     千年(ChronoUnit.MILLENNIA
     十亿年(一个纪元)(ChronoUnit.ERAS
     2.92277266×1011年(永恒)(ChronoUnit.FOREVER
  实例: 获取举例今天100年以后的本地日期时间
      LocalDate DecadesFromNow = LocalDate.now().plus(1,ChronoUnit.DECADES);
--------------------------------------------------------------------------------------
  TemporalUnit是个接口,一般直接使用该接口在Java8自带的实现类即可(ChronoUnit)
  idea查看uml图方式=> IDEA使用常见问题记录 的2.1.3 uml图
在这里插入图片描述

f. 日期判断 isAfter(isBefore)

两个比较的对象类型需要一致
  isAfter(ChronoLocalDateTime<?> other)** :检查这个日期时间是否在指定的日期之后。   **isBefore(ChronoLocalDateTime<?> other) :检查这个日期时间是否在指定的日期之前。

    public static void main(String[] args) {
        boolean after1 = Instant.now().isAfter(Instant.now());
        boolean after2 = LocalDateTime.now().isAfter(LocalDateTime.now());
        boolean after3 = LocalDate.now().isAfter(LocalDate.now());
        boolean after4 = LocalTime.now().isAfter(LocalTime.now());
        boolean after5 = OffsetDateTime.now().isAfter(OffsetDateTime.now());
        boolean after6 = ZonedDateTime.now().isAfter(ZonedDateTime.now());
    }

g. 日期调节器 with

  按照一定规则(例如:“下个星期一”,“当月的15号”,“当年的第1个周一”)对日期对象修改,并返回一个符合条件的新日期对象


g1. with + 调节器

  日期调节器 with(TemporalAdjuster adjuster) 的参数 TemporalAdjuster 一般通过 Java8自带的调节器 TemporalAdjusters 返回值

id类名作用
19TemporalAdjusters
调节器
  类中所有方法都会返回一个 TemporalAdjuster 对象。
  表示一些 常用时间节点,供时间计算。(常用 g. 日期调节器 with:作为*.with的参数,按照一些特殊规则计算时间)
  例如: 上一个星期几(TemporalAdjusters.previous(DayOfWeek dayOfWeek)
      上一个星期几或当天(TemporalAdjusters.previousOrSame(DayOfWeek dayOfWeek)
      下一个星期几(TemporalAdjusters.next(DayOfWeek dayOfWeek)
      下一个星期几或当天(TemporalAdjusters.nextOrSame(DayOfWeek dayOfWeek)
      当月第1天(TemporalAdjusters.firstDayOfMonth()
      当月最后1天(TemporalAdjusters.lastDayOfMonth()()
      当月第1个星期几(TemporalAdjusters.firstInMonth(DayOfWeek dayOfWeek)
      当月第n个星期几(TemporalAdjusters.dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)
      当月最后一个星期几(TemporalAdjusters.lastInMonth(DayOfWeek dayOfWeek)
      当年最后1天(TemporalAdjusters.lastDayOfYear()
      明年的第1天(TemporalAdjusters.firstDayOfNextYear()
      下月第1天(TemporalAdjusters.firstDayOfNextMonth()
      lambda表达式自定义指定日期(TemporalAdjusters.
                ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster)
  实例: 获取举例今天100年以后的日期
      LocalDate DecadesFromNow = LocalDate.now().plus(1,ChronoUnit.DECADES);
--------------------------------------------------------------------------------------
  Class TemporalAdjusters 并不是 interface TemporalAdjuster 的实现类,只不过 Class TemporalAdjusters 的静态方法实现了 interface TemporalAdjuster,并返回 interface TemporalAdjuster 对象的实例

  这里以 DayOFWeek 举例,详细内容查看 5.新API详解 id=2 DayOfWeek星期枚举

  DayOfWeek 可以作为 -> with 方法的参数调节日期,例如:获取"下个星期五"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        //可以作为 -> with 方法的参数调节日期,例如:获取"下个星期五"的日期
        TemporalAdjuster previous = TemporalAdjusters.next(DayOfWeek.of(5));
        LocalDateTime nextFriday = ldt.with(previous);
        //2022-01-01T00:00是星期六,他的下一个周五日期是2022-01-07T00:00
        System.out.println(ldt + "是" + ldt.getDayOfWeek().
                getDisplayName(TextStyle.FULL, Locale.CHINESE) +
                                   ",他的下一个周五日期是" + nextFriday);
    }

  DayOfWeek 可以作为判断条件 -> with 方法中自定义接口,实现同样功能:获取"下个星期五"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        //可以作为判断条件 -> with 方法中自定义接口,实现同样功能:获取"下个星期五"的日期。
        LocalDateTime nextFriday = ldt.with(new TemporalAdjuster() {
            @Override
            public Temporal adjustInto(Temporal temporal) {
                //获取当前日期是星期几
                int i = temporal.get(ChronoField.DAY_OF_WEEK);
                DayOfWeek dayOfWeekNow = DayOfWeek.of(i);
                if (dayOfWeekNow == DayOfWeek.MONDAY) return temporal.plus(4, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.TUESDAY) return temporal.plus(3, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.WEDNESDAY) return temporal.plus(2, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.THURSDAY) return temporal.plus(1, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.FRIDAY) return temporal;
                else if (dayOfWeekNow == DayOfWeek.SATURDAY) return temporal.plus(6, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.SUNDAY) return temporal.plus(5, ChronoUnit.DAYS);
                return null;
            }
        });
        //2022-01-01T00:00是星期六,他的下一个周五日期是2022-01-07T00:00
        System.out.println(ldt + "是" + ldt.getDayOfWeek().
                getDisplayName(TextStyle.FULL, Locale.CHINESE) +
                                   ",他的下一个周五日期是" + nextFriday);
    }

  或者通过 TemporalAdjusters.ofDateAdjuster

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        //可以作为判断条件 -> with 方法中自定义接口,实现同样功能:获取"下个星期五"的日期。
        TemporalAdjuster nextFridayAdjuster = TemporalAdjusters.ofDateAdjuster(new UnaryOperator<LocalDate>() {
            @Override
            public LocalDate apply(LocalDate localDate) {
                //获取当前日期是星期几
                int i = localDate.get(ChronoField.DAY_OF_WEEK);
                DayOfWeek dayOfWeekNow = DayOfWeek.of(i);
                if (dayOfWeekNow == DayOfWeek.MONDAY) return localDate.plus(4, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.TUESDAY) return localDate.plus(3, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.WEDNESDAY) return localDate.plus(2, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.THURSDAY) return localDate.plus(1, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.FRIDAY) return localDate;
                else if (dayOfWeekNow == DayOfWeek.SATURDAY) return localDate.plus(6, ChronoUnit.DAYS);
                else if (dayOfWeekNow == DayOfWeek.SUNDAY) return localDate.plus(5, ChronoUnit.DAYS);
                return null;
            }
        });
        LocalDateTime nextFriday = ldt.with(nextFridayAdjuster);
        //2022-01-01T00:00是星期六,他的下一个周五日期是2022-01-07T00:00
        System.out.println(ldt + "是" + ldt.getDayOfWeek().
                getDisplayName(TextStyle.FULL, Locale.CHINESE) +
                                   ",他的下一个周五日期是" + nextFriday);
    }

g2. with + 时间结界

  见 => 5. 新API详解 ,id=24 ChronoField 时间结界


g3. withNano 纳秒

  获取当前时间的"纳秒数调整为1"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withNano(1);
        //原时间:2022-01-01T00:00,修改后:2022-01-01T00:00:00.000000001
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g4. withSecond 秒

  获取当前时间的"秒数调整为2"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withSecond(2);
        //原时间:2022-01-01T00:00,修改后:2022-01-01T00:00:02
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g5. withMinute 分钟

  获取当前时间的"分钟调整为3"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withMinute(3);
        //原时间:2022-01-01T00:00,修改后:2022-01-01T00:03
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g6. withHour 小时

  获取当前时间的"小时调整为4"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withHour(4);
        //原时间:2022-01-01T00:00,修改后:2022-01-01T04:00
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g7. withDayOfMonth 第n天(月中)

  获取当前时间的"月中第5天"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withDayOfMonth(5);
        //原时间:2022-01-01T00:00,修改后:2022-01-05T00:00
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g8. withDayOfYear 第n天(年中)

  获取当前时间的"年中第60天"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withDayOfYear(60);
        //原时间:2022-01-01T00:00,修改后:2022-03-01T00:00
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g9. withMonth 月

  获取当前时间的"月调整为7"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withMonth(7);
        //原时间:2022-01-01T00:00,修改后:2022-07-01T00:00
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g10. withYear 年

  获取当前时间的"年调整为8"的日期。

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime withNano = ldt.withYear(8);
        //原时间:2022-01-01T00:00,修改后:0008-01-01T00:00
        System.out.println("原时间:" + ldt + ",修改后:" + withNano);
    }

g11. 结合query使用

  见 =>h. 日期查询 query


h. 日期查询 query

  <= g. 自定义调节器 with

  节日查询:“假设今天是2022年5月31日,计算出距离下个圣诞节(12.28)、儿童节(6.1)、劳动节(5.1)分别还有多少天”。

    public static void main(String[] args) {
        //创建日期对象2022年5月31日,模拟计算
        LocalDate today = LocalDate.of(2022, 5, 31);
        HashMap<String, Long> queryResult = today.query(new TemporalQuery<HashMap<String, Long>>() {
            @Override
            //TemporalAccessor是LocalDateTime、LocalDate的顶级父类接口
            //相当于LocalDate就是这个接口的实现类,将temporal转换为LocalDate进行使用。
            public HashMap<String, Long> queryFrom(TemporalAccessor temporalAccessor) {
                //1.将 temporalAccessor 转为LocalDate对象
                LocalDate ld = LocalDate.from(temporalAccessor);
                //2.创建容器
                HashMap<String, LocalDate> ldMap = new HashMap<>();
                HashMap<String, Long> resultMap = new HashMap<>();
                //3.封装当年的圣诞节/儿童节/劳动节的时间对象
                ldMap.put("圣诞节", LocalDate.of(ld.getYear(), Month.DECEMBER, 2));
                ldMap.put("儿童节", LocalDate.of(ld.getYear(), Month.JUNE, 1));
                ldMap.put("劳动节", LocalDate.of(ld.getYear(), Month.MAY, 1));
                //4.判断date是否已经超过了d1/d2/d3三个节日,如果超过了,则计算下一年的日期
                for (String key : ldMap.keySet()) {
                    LocalDate holidayDate = ldMap.get(key);
                    //如果当前时间>当年节日,则节日日期+1年
                    if (ld.isAfter(holidayDate)) holidayDate = holidayDate.plusYears(1);
                    //计算:距离该节日还差几天
                    resultMap.put(key, ChronoUnit.DAYS.between(ld, holidayDate));
                }
                //5.返回结果
                return resultMap;
            }
        });
        //打印结果
        for (String holidayName : queryResult.keySet()) {
            //距离下一个儿童节还剩1天
            //距离下一个劳动节还剩335天
            //距离下一个圣诞节还剩185天
            System.out.println("距离下一个" + holidayName + "还剩" + queryResult.get(holidayName) + "天");
        }
    }

i. 日期解析 format(日期 -> String)⭐️

i1. 标准的ISO日期格式 DateTimeFormatter.❓

id类名作用
21DateTimeFormatter  日期格式化器,用于打印和解析日期时间对象。(常用 i. 日期解析 format(日期->String):作为*.with的参数,按照一些特殊规则计算时间)
  常用方法:
    DateTimeFormatter.ofLocalizedDate 静态方法,自动识别时区的方式解析,需要传入一个FormatStyle的枚举值
    DateTimeFormatter.ofPattern 静态方法,指定日期格式的解析,需要传入一个字符串日期格式
  实例:
    String format1 = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE);
    String format2 = LocalDateTime.now().format(DateTimeFormatter.ofPattern(“yyyy-MM-dd’T’HH:mm:ss.SSS”));
--------------------------------------------------------------------------------------
  DateTimeFormatter预制的格式化器,最常用的两个:
  1. yyyy-MM-dd
    DateTimeFormatter.ISO_DATE
      => 2022-01-18
  2. yyyy-MM-dd’T’HH:mm:ss.SSS
    DateTimeFormatter.ISO_DATE_TIME
      =>2022-01-18T18:12:51.639
--------------------------------------------------------------------------------------
  带不带 LOCAL 的对比: 仅对 OffsetDateTime、ZonedDateTime 有区别
  1. LocalDateTime + ISO_DATE_TIME
    LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639
  2. LocalDateTime + ISO_LOCAL_DATE_TIME
    LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T18:12:51.639
  3. OffsetDateTime + ISO_DATE_TIME
    OffsetDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639+08:00
  4. OffsetDateTime + ISO_LOCAL_DATE_TIME
    OffsetDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T11:12:51.639
  5. ZonedDateTime + ISO_DATE_TIME
    ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
      => 2022-01-18T18:12:51.639+08:00[Asia/Shanghai]
  6. ZonedDateTime + ISO_LOCAL_DATE_TIME
    ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
      => 2022-01-18T18:12:51.639
	public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.now();
        String format1 = ldt.format(DateTimeFormatter.ISO_DATE);
        String format2 = ldt.format(DateTimeFormatter.ISO_DATE_TIME);
        String format3 = ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"));
        System.out.println(format1);//2022-01-18
        System.out.println(format2);//2022-01-18T18:12:51.639
        System.out.println(format2);//2022-01-18T18:12:51.639
	}

i2. 自动识别时区 DateTimeFormatter.ofLocalizedDate(FormatStyle.❓))

id类名作用
22 Enum FormatStyle  枚举本地化日期,时间或日期时间格式化的风格。(常用 i. 日期解析 format(日期->String):作为 DateTimeFormatter.ofLocalizedDate(FormatStyle dateStyle) 静态方法的参数使用,并返回一个 DateTimeFormatter 对象)
  例如: 全文格式(FormatStyle.FULL)=> 2022年1月18日 星期二
      长文本格式(FormatStyle.LONG)=> 2022年1月18日
      中等格式(FormatStyle.MEDIUM)=> 2022-1-18
      短文格式(FormatStyle.SHORT)=> 22-1-18
  实例: 全文格式解析本地日期时间
  String format =
     LocalDateTime.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
--------------------------------------------------------------------------------------
  需要注意 这种方式在不同时区的显示内容不一样,在其他时区不会显示中文

  ofLocalizedDate表示自动根据时区识别本地格式,通过指定 全/长/中/短 几种格式来解析日期。

	public static void main(String[] args) {
		LocalDateTime ldt = LocalDateTime.now();
		String fullTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
		String longTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
		String mediumTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM));
		String shortTime = ldt.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT));
		System.out.println(fullTime);//2022年1月18日 星期二
		System.out.println(longTime);//2022年1月18日
		System.out.println(mediumTime);//2022-1-18
		System.out.println(shortTime);//22-1-18
	}

j. 日期解析 parse 方法(String -> 日期)

  直接使用静态方法parse但不符合格式的字符串会解析失败

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.parse("2022-01-18T18:12:51.639");
        System.out.println(ldt);//2022-01-18T18:12:51.639

        LocalDate ld = LocalDate.parse("2022-01-18T18:12:51.639");
        //java.time.format.DateTimeParseException:
        //Text '2022-01-18T18:12:51.639' could not be parsed, unparsed text found at index 10
        System.out.println(ld);
    }

4. 新API实例 - 时间段类


k. 实例化对象 of


k1. Duration.of(数量,单位)

  这里需要传入2个参数,数量单位,单位一般使用jdk8自带的实现类ChronoUnit(详情见 5. 新API详解 => id=14 ChronoUnit 时间单位枚举),也可以自定义 TemporalAmount 接口的实现类;

id类名作用
14 Enum ChronoUnit  TemporalAmount 接口的实现类,采用枚举类的方式表示一些 计算常用时间单位。(常用 e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  例如: 一纳秒(ChronoUnit.NANOS
      一微秒(ChronoUnit.MICROS
      一毫秒(ChronoUnit.MILLIS
      一秒(ChronoUnit.SECONDS
      一分钟(ChronoUnit.MINUTES
     一小时(ChronoUnit.HOURS
     半天(ChronoUnit.HALF_DAYS
     一天(ChronoUnit.DAYS
     一周(ChronoUnit.WEEKS
     一个月(ChronoUnit.MONTHS
     一年(ChronoUnit.YEARS
     十年(ChronoUnit.DECADES
     百年(一个世纪)(ChronoUnit.CENTURIES
     千年(ChronoUnit.MILLENNIA
     十亿年(一个纪元)(ChronoUnit.ERAS
     2.92277266×1011年(永恒)(ChronoUnit.FOREVER
  实例: 获取举例今天100年以后的本地日期时间
      LocalDate DecadesFromNow = LocalDate.now().plus(1,ChronoUnit.DECADES);
--------------------------------------------------------------------------------------
  TemporalUnit是个接口,一般直接使用该接口在Java8自带的实现类即可(ChronoUnit)
  idea查看uml图方式=> IDEA使用常见问题记录 的2.1.3 uml图
在这里插入图片描述
实例: 2022年1月1日0点0分0秒,加1纳秒。
    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);

        Duration duration1 = Duration.of(1, ChronoUnit.NANOS);//一纳秒
        /*
        Duration duration2 = Duration.of(1, ChronoUnit.MICROS);//一微秒
        Duration duration3 = Duration.of(1, ChronoUnit.MILLIS);//一毫秒
        Duration duration4 = Duration.of(1, ChronoUnit.SECONDS);//一秒
        Duration duration5 = Duration.of(1, ChronoUnit.MINUTES);//一分钟
        Duration duration6 = Duration.of(1, ChronoUnit.HOURS);//一小时
        Duration duration7 = Duration.of(1, ChronoUnit.HALF_DAYS);//半天
        Duration duration8 = Duration.of(1, ChronoUnit.DAYS);//一天
        */
        try {
            Duration duration9 = Duration.of(1, ChronoUnit.WEEKS);//一周
            /*
            Duration duration10 = Duration.of(1, ChronoUnit.MONTHS);//一月
            Duration duration11 = Duration.of(1, ChronoUnit.YEARS);//一年
            Duration duration12 = Duration.of(1, ChronoUnit.DECADES);//十年
            Duration duration13 = Duration.of(1, ChronoUnit.CENTURIES);//百年(一个世纪)
            Duration duration14 = Duration.of(1, ChronoUnit.MILLENNIA);//千年
            Duration duration15 = Duration.of(1, ChronoUnit.ERAS);//十亿年(一个纪元)
            Duration duration16 = Duration.of(1, ChronoUnit.FOREVER);//2.92277266×1011年(永恒)
         	*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        LocalDateTime plus = ldt.plus(duration1);
        System.out.println("原始时间  :" + ldt);
        System.out.println("修改后时间:" + plus);
    }

运行结果:

java.time.temporal.UnsupportedTemporalTypeException: Unit must not have an estimated duration
	at java.time.Duration.plus(Duration.java:701)
	at java.time.Duration.of(Duration.java:308)
	at com.groupies.jdk8.day04....
原始时间  :2022-01-01T00:00
修改后时间:2022-01-01T00:00:00.000000001

  出现报错信息 Unit must not have an estimated duration(单位必须不包含估计的时间) ,首先来定位一下源码,查找错误原因

step1. Duration of(long amount, TemporalUnit unit)源码:
在这里插入图片描述
step2. 找到报错的出处:
在这里插入图片描述
step3. 关于isDurationEstimated的解释:
在这里插入图片描述

step4. ChronoUnit中关于isDurationEstimated的定义:
在这里插入图片描述

step5. Duration.of(数量,单位)取值范围总结:

类型类名作为Duration.of的参数
估算值
estimate
一纳秒(ChronoUnit.NANOS
一微秒(ChronoUnit.MICROS
一毫秒(ChronoUnit.MILLIS
一秒(ChronoUnit.SECONDS
一分钟(ChronoUnit.MINUTES
一小时(ChronoUnit.HOURS
半天(ChronoUnit.HALF_DAYS
一天(ChronoUnit.DAYS
可以
准确值
exact value
一周(ChronoUnit.WEEKS
一个月(ChronoUnit.MONTHS
一年(ChronoUnit.YEARS
十年(ChronoUnit.DECADES
百年(一个世纪)(ChronoUnit.CENTURIES
千年(ChronoUnit.MILLENNIA
十亿年(一个纪元)(ChronoUnit.ERAS
2.92277266×1011年(永恒)(ChronoUnit.FOREVER
不可以

k2. Duration.ofNanos(纳秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofNanos(1);
        //2022-01-01T00:00 => 2022-01-01T00:00:00.000000001
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k3. Duration.ofMillils(毫秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofMillis(2);
        //2022-01-01T00:00 => 2022-01-01T00:00:00.002
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k4. Duration.ofSeconds(秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofSeconds(3);
        //2022-01-01T00:00 => 2022-01-01T00:00:03
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k5. Duration.ofSeconds(秒,纳秒)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofSeconds(4,5);
        //2022-01-01T00:00 => 2022-01-01T00:00:04.000000005
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k6. Duration.ofMinutes(分钟)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofMinutes(6);
        //2022-01-01T00:00 => 2022-01-01T00:06
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k7. Duration.ofHours(小时)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofHours(7);
        //2022-01-01T00:00 => 2022-01-01T07:00
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k8. Duration.ofDays(天)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Duration duration = Duration.ofDays(8);
        //2022-01-01T00:00 => 2022-01-09T00:00
        LocalDateTime plus = ldt.plus(duration);
		System.out.println(ldt + " =>" + plus);
    }

k9. Period.of(年,月,日)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.of(1, 2, 3);
        //2022-01-01T00:00 => 2023-03-04T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k10. Period.ofDays(日)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofDays(4);
        //2022-01-01T00:00 => 2022-01-05T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k11. Period.ofWeeks(周)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofWeeks(5);
        //2022-01-01T00:00 => 2022-02-05T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k12. Period.ofMonths(月)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofWeeks(5);
        //2022-01-01T00:00 => 2022-07-01T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

k13. Period.ofYears(年)

    public static void main(String[] args) {
        LocalDateTime ldt = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        Period period = Period.ofYears(7);
        //2022-01-01T00:00 => 2029-01-01T00:00
        LocalDateTime plus = ldt.plus(period);
		System.out.println(ldt + " =>" + plus);
    }

l. 时间间隔 between


l1. 范围间隔 Duration.between

  支持LocalDateTime、LocalTime、Instant等秒级(Second)信息的时间对象;传入LocalDate类型可以通过编译,运行时会提示 Unsupported unit: Seconds;

    public static void main(String[] args) {
        LocalDateTime ldt1 = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime ldt2 = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        System.out.println(Duration.between(ldt1,ldt2));

        LocalDate ld1 = LocalDate.of(2022, 1, 1);
        LocalDate ld2 = LocalDate.of(2000, 1, 1);
        System.out.println(Duration.between(ld1, ld2));
    }

在这里插入图片描述


l2. 范围间隔 Period.between

  仅支持LocalDate类型,传入其他类型编译不通过

    public static void main(String[] args) {
        LocalDate ld1 = LocalDate.of(2022, 1, 1);
        LocalDate ld2 = LocalDate.of(2000, 1, 1);
        //P-22Y
        System.out.println(Period.between(ld1, ld2));

        LocalDateTime ldt1 = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
        LocalDateTime ldt2 = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        System.out.println(Period.between(ldt1,ldt2));
    }

请添加图片描述


l3. 时间单位间隔 ChronoUnit.❓ .between

  ChronoUnit共16种类型,时间单位也有Instant、LocalDate、LocalTime、LocalDateTime…等多种类型,排列组合方式过多,这里仅测试了LocalDate&ChronoUnit.between 之间的关系;

id类名作用
14 Enum ChronoUnit  TemporalAmount 接口的实现类,采用枚举类的方式表示一些 计算常用时间单位。(常用 e.日期加减:作为plus,minus方法的参数,指定计算的最小单位)
  例如: 一纳秒(ChronoUnit.NANOS
      一微秒(ChronoUnit.MICROS
      一毫秒(ChronoUnit.MILLIS
      一秒(ChronoUnit.SECONDS
      一分钟(ChronoUnit.MINUTES
     一小时(ChronoUnit.HOURS
     半天(ChronoUnit.HALF_DAYS
     一天(ChronoUnit.DAYS
     一周(ChronoUnit.WEEKS
     一个月(ChronoUnit.MONTHS
     一年(ChronoUnit.YEARS
     十年(ChronoUnit.DECADES
     百年(一个世纪)(ChronoUnit.CENTURIES
     千年(ChronoUnit.MILLENNIA
     十亿年(一个纪元)(ChronoUnit.ERAS
     2.92277266×1011年(永恒)(ChronoUnit.FOREVER
    public static void main(String[] args) {
        LocalDate ld1 = LocalDate.of(2022, 1, 1);
        LocalDate ld2 = LocalDate.of(2000, 1, 1);
        System.out.println("YEARS:" + ChronoUnit.YEARS.between(ld1, ld2));
        System.out.println("MONTHS:" + ChronoUnit.MONTHS.between(ld1, ld2));
        System.out.println("WEEKS:" + ChronoUnit.WEEKS.between(ld1, ld2));
        System.out.println("DECADES:" + ChronoUnit.DECADES.between(ld1, ld2));
        System.out.println("DAYS:" + ChronoUnit.DAYS.between(ld1, ld2));
        System.out.println("HOURS:" + ChronoUnit.HOURS.between(ld1, ld2));
        System.out.println("MINUTES:" + ChronoUnit.MINUTES.between(ld1, ld2));
        System.out.println("SECONDS:" + ChronoUnit.SECONDS.between(ld1, ld2));
    }

LocalDate对象没有小时的信息,所以不支持计算小时级别时间范围
在这里插入图片描述


5. 新API详解


id=2 DayOfWeek 星期枚举

  文章过长不能保存,内容发布在另一篇blog => 3.1_28_1 JDK8新特性【Date】之DayOfWeek 星期枚举


id=4 Month 月枚举

  文章过长不能保存,内容发布在另一篇blog => 3.1_28_2 JDK8新特性【Date】之Month 月枚举


id=14 ChronoUnit 时间单位枚举

  文章过长不能保存,内容发布在另一篇blog => JDK8新特性【Date】之ChronoUnit 时间单位枚举


id=16 ZoneId 时区信息

  文章过长不能保存,内容发布在另一篇blog => JDK8新特性【Date】之ZoneId 时区信息


id=24 ChronoField 时间结界

  文章过长不能保存,内容发布在另一篇blog => DK8新特性【Date】之ChronoField 时间结界


6.旧API转换


  对于老项目的改造,需要将 Date 或者 Calendar 转换为 java.time 包中相应的类。这里总结了一些类的转换过程。
    6.1 java.util.Date -> java.sql.Date
    6.2 java.util.Date -> java.time.Instant
    6.3 java.util.Date -> java.time.LocalDate
    6.4 java.sql.Date -> java.util.Date
    6.5 java.sql.Date -> java.time.Instant
    6.6 java.sql.Date -> java.time.LocalDate
    6.7 java.sql.Timestamp -> java.time.Instant
    6.8 java.sql.Timestamp -> java.time.toLocalDate
    6.9 java.util.Calendar -> java.time.LocalDateTime
    6.10 java.util.Calendar -> java.time.ZonedDateTime

  文章过长不能保存,内容发布在另一篇blog => JDK8新特性【Date】之旧API转换


7. 注意事项


7.1 对比 OffsetDateTime & ZonedDateTime

  LocalDateTime、OffsetDateTime、ZonedDateTime这三个哥们,LocalDateTime比较好理解,一般都没有异议。关于OffsetDateTime和ZonedDateTime对比如下:

组成:
  1. OffsetDateTime: = LocalDateTime + ZoneOffset(偏移量)
  2. ZonedDateTime: = LocalDateTime + ZoneId(时区信息)

偏移值:
  1. OffsetDateTime可以设置 偏移值
  2. ZonedDateTime无法设置 偏移值

夏令时:
  1. OffsetDateTime无法支持 夏令时调整
  2. ZonedDateTime可以支持 夏令时调整

区别:  等于ZoneOffset和ZoneId的区别
  1. OffsetDateTime:代表一个瞬时值 ,《0时区 + 固定偏移量》 计算出来的
  2. ZonedDateTime:代表一个动态计算值,《0时区 + 动态偏移量》(根据当时的规则)计算出来的

使用场景:
  1. OffsetDateTime:由于其不变性的特点,主要用于传递数据数据库存储网络通信

  2. ZonedDateTime:由于其时区性的特点,主要用于在特定时区里做时间显示


7.2 新API的 == 和 equals

  1. ==: ×,比较的是两个对象在堆中的内存地址。
  2. equals()方法: √ ,equals()方法继承自Object类,所有Object的子类都可以重写该方法,新版时间API重写该方法后,比较的是时间的值。
  是由于新版API时间对象不可变特性(为了更好地支持多线程),每次对时间的计算都会返回一个新的时间对象,新的对象也就意味着新的堆内存地址,所以新版时间API比较时间时,要采用 equals(): 方式比较。


7.3 指定时区

  构造日期时间对象时指定时区。为了明确代码意图,消除语义上的不确定性。


22/02/11

M

注释

  1. Unix 时间戳 Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 ↩︎

  2. 纪元时间 指1970年1月1日格林威治午夜12点为起点,纪元日的定义与UNIX发展历史有关。 ↩︎

  3. 月对齐 重新定义一个关于星期几的新规则,规则描述:每月的1日作为周一(1.1日/2.1日/…12.1日),例如"2022年2月1日"是星期二,但在月对齐(ALIGNED_xxxx_MONTH)的新规则下,"2022年2月1日"是星期一。 ↩︎

  4. 年对齐 重新定义一个关于星期几的新规则,规则描述:每年的1月1日作为周一,例如"2022年1月1日"是星期六,但在年对齐(ALIGNED_xxxx_YEAR)的新规则下,"2022年1月1日"是星期一 ↩︎

  5. 公元 公历纪年法,是一种源自于西方社会的纪年方法。原称基督纪元,又称西历或西元。 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值