likes
comments
collection
share

Java8日期处理【下】(超详细、JDK8)

作者站长头像
站长
· 阅读数 18

一:序

Java8日期处理【下】(超详细、JDK8)

二:日期时间格式化及转换

  在开发中会经常会遇到将一个日期字符串转换成对应的日期时间对象,有时又会遇到将日期时间对象转换成一个日期字符串,这样就构成了日期时间字符串和日期对象互转;在Java8中针对这些需求也是有对应的方法,比如:parse()方法就是将对象转换为字符串、format()方法就是将字符串转换成对象。   注意的是:Clock、ZoneId、ZoneOffset类是没有parse()方法的,而Clock、Duration、Instant、Period、ZoneOffset类是不含format()方法的。   最后还有一个关键的DateTimeFormatter类,它是日期时间格式化类,允许将日期时间对象格式化为字符串,或者将字符串解析为日期时间对象。它的设计旨在取代旧的SimpleDateFormat,且提供了线程安全性,并支持更多灵活的日期时间格式化和解析选项。

(一):快速入门

  可以说下面的快速入门基本上就可以应对日常开发了,但需要深入的了解则需要继续往下看。

public static void main(String[] args) {
    // 创建现在的日期时间
    LocalDateTime ldt = LocalDateTime.now();
    System.out.println("默认格式化打印:" + ldt);
    // 打印:默认格式化打印:2024-07-25T13:53:04.789
    
    // 转换为特定格式的字符串
    DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateStr = ldt.format(pattern);
    System.out.println("使用指定样式格式化:" + dateStr);
    // 打印:使用指定样式格式化:2024-07-25 13:53:04
    
    // 将字符串日期转换为对应的对象(默认)
    String str1 = "2024-07-25T13:53:04.789";
    System.out.println(LocalDateTime.parse(str1));
    // 打印:2024-07-25T13:53:04.789
    
    // 将字符串日期转换为对应的对象(其它类型日期字符串)
    String str2 = "2024-07-25 13:53:04";
    System.out.println(LocalDateTime.parse(str2, pattern));
    // 打印:2024-07-25T13:53:04
}

(二):使用预定义格式化器

  在快速入门案例中我们要定义一个日期时间的格式化器都是用DateTimeFormatter.ofPattern("xxx")来手动定义格式化器,但是这个类为我们定义了可能需要用到的格式方式,具体如下:   使用自带的格式化器得注意一点,有的格式化是针对带有时区的日期时间来格式化的,没有时区信息的话会报错,如LocalDateTime对象用ISO_INSTANT、ISO_OFFSET_DATE_TIME等都会报错。还有就是日期不带时间,但格式化用到了时间也会报错。

点开查看详情:DateTimeFormatter自带的格式化器
DateTimeFormatter.BASIC_ISO_DATE
    格式:yyyyMMdd,例如:20240725
    用途:基本的ISO日期格式,适合数据交换,没有分隔符。
 
DateTimeFormatter.ISO_DATE
    格式:yyyy-MM-dd,例如:2024-07-25
    用途:ISO日期格式,包含年、月、日。
DateTimeFormatter.ISO_TIME
    格式:HH:mm:ss,例如 15:30:00
    用途:ISO时间格式,包含时、分、秒。
DateTimeFormatter.ISO_DATE_TIME
    格式:yyyy-MM-ddTHH:mm:ss,例如:2024-07-25T15:30:00
    用途:ISO日期时间格式,包含年、月、日、时、分、秒。
 
DateTimeFormatter.ISO_LOCAL_DATE
    格式:yyyy-MM-dd,例如:2024-07-25
    用途:本地日期格式,不包含时区信息。
DateTimeFormatter.ISO_LOCAL_TIME
    格式:HH:mm:ss,例如 15:30:00
    用途:本地时间格式,不包含日期和时区信息。
DateTimeFormatter.ISO_LOCAL_DATE_TIME
    格式:yyyy-MM-ddTHH:mm:ss,例如 2024-07-25T15:30:00
    用途:本地日期时间格式,不包含时区信息。
 
DateTimeFormatter.ISO_INSTANT
    格式:yyyy-MM-ddTHH:mm:ssZ,例如:2024-07-25T15:30:00Z。
    用途:ISO格式的即时时间,带有时区信息。
 
DateTimeFormatter.ISO_OFFSET_DATE
    格式:yyyy-MM-ddZZZZZ,例如 2024-07-25+08:00
    用途:带偏移量的ISO日期格式,包含年、月、日和时区偏移量。
DateTimeFormatter.ISO_OFFSET_TIME
    格式:HH:mm:ssZZZZZ,例如 15:30:00+08:00
    用途:带偏移量的ISO时间格式,包含时、分、秒和时区偏移量。
DateTimeFormatter.ISO_OFFSET_DATE_TIME
    格式:yyyy-MM-ddTHH:mm:ssZZZZZ,例如 2024-07-25T15:30:00+08:00
    用途:带偏移量的ISO日期时间格式,包含年、月、日、时、分、秒和时区偏移量。
 
DateTimeFormatter.ISO_ORDINAL_DATE
    格式:yyyy-DDD,例如 2024-206
    用途:ISO序数日期格式,包含年和一年中的第几天。
DateTimeFormatter.ISO_WEEK_DATE
    格式:yyyy-Www-D,例如 2024-W30-3
    用途:ISO周日期格式,包含年、周数和星期几(从1开始)。
DateTimeFormatter.ISO_ZONED_DATE_TIME
    格式:yyyy-MM-ddTHH:mm:ssZ[XXXXX],例如:2024-07-25T14:16:08.889+08:00[Asia/Shanghai]
    用途:带时区的ISO日期时间格式,包含年、月、日、时、分、秒和时区信息。
DateTimeFormatter.RFC_1123_DATE_TIME
    格式:EEE, dd MMM yyyy HH:mm:ss z,例如:Thu, 25 Jul 2024 14:16:08 +0800
    用途:RFC 1123日期时间格式,常用于HTTP协议等,带有星期几、月份缩写、年、时、分、秒和时区信息。
public static void main(String[] args) {
    // 创建一个带时区的现在时间
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    // 创建一个不带时区的现在时间
    LocalDateTime localDateTime = LocalDateTime.now();
    // 创建一个不带时区的日期
    LocalDate localDate = LocalDate.now();
    
    // 关于ZonedDateTime的日期时间格式化
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_TIME));
    // 打印:16:07:53.643+08:00
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_DATE));
    // 打印:2024-07-25+08:00
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_DATE_TIME));
    // 打印:2024-07-25T16:07:53.643+08:00[Asia/Shanghai]
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_INSTANT));
    // 打印:2024-07-25T08:07:53.643Z  说明:INSTANT是不得时区的
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    // 打印:2024-07-25T16:07:53.643
    System.out.println(zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
    // 打印:2024-07-25T16:07:53.643+08:00
    
    // 关于LocalDateTime的日期时间格式化
    System.out.println(localDateTime.format(DateTimeFormatter.ISO_DATE));
    // 打印:2024-07-25
    // 下面会报错,LocalDateTime里没有时区信息
    // System.out.println(localDateTime.format(DateTimeFormatter.ISO_INSTANT));
    
    // 关于LocalDate的日期格式化
    System.out.println(localDate.format(DateTimeFormatter.ISO_DATE));
    // 打印:2024-07-25
    // 下面会报错,LocalDate里没有时间对象
    // System.out.println(localDate.format(DateTimeFormatter.ISO_TIME));
}

(三):格式化符号说明

  若我们想自定义格式化字符就需要自己写了,比如我们常见的:yyyy-MM-dd HH:mm:ss就是按照下面的不同字符进行组装的,具体就来看看吧。

点开查看详情:DateTimeFormatter中使用的格式化字符说明
'假设当前的日期时间(带时区)为:2024-02-23T12:10:30.000009999+08:00[Asia/Shanghai]'
    '## 年、月、日、星期的一些格式化字符'
        G(纪元年份):纪元标记,输出如:AD(代表公元)、BC(代表公元前)
            注:根据不同的地区输出也不一样,中国区域输出:公元;
            若输出英文则可以为DateTimeFormatter对象实例设置xx.withLocale(Locale.ENGLISH);
        y(年份):yy表示两位年份,y或yyyy表示4位年份;如yy=24、y或yyyy=2024
        u(年份):uu表示两位年份,u或uuuu表示4位年份;如uu=24、u或uuuu=2024;(基本和y没啥区别)
        D(年份中的天数):表示当天是当年的第几天(包含当天);如54
        M/L(月份):两个符号一样,输出四种类型月份;如M=2、MM=02、MMM=Feb、MMMM=February;
        d(月份中的天数):月份中的天数;如d=23(写一个d则1~9不会进行补0)、dd=23
        Q/q(季度):一年中的季度;如:Q=1、QQ=01、QQQ=1季、QQQQ=第一季度
        Y(周年):YYYY表示四位数的年份,YY表示两位数的年份,Y表示周年的年份。
        w(一年中的周数):如w=8、ww=08
        W(当月中的周数):如W=4
        E(月份中的星期几):如E=Fri、EEEE=Friday;这是在Locale.ENGLISH中输出的情况。
        e/c(月份中的星期几):e和c一样。如e=6、ee=06、eee=Fri、eeee=Friday;注:周日为01、周六为07
        F(月份):只能表示1~12月份,且月份前无法补0;如F=2
 
    '## 时、分、秒、毫秒、纳秒的一些格式化字符:'
        a(上午下午):可以以表示AM(0~11)、PM(12~23);如a=PM(在China区域显示下午)
        h(一天中的小时数1~12):h表示1~9小时不带前缀0的小时、hh表示1~9小时带前缀0
        k(一天中的小时数1~24):k表示1~9小时不带前缀0的小时、kk表示1~9小时带前缀0
        K(一天中的小时数0~11):K表示0~9小时不带前缀0的小时、KK表示0~9小时带前缀0
        H(一天中的小时数0~23):H表示0~9小时不带前缀0的小时、HH表示0~9小时带前缀0
        m(分钟):m表示0~9分钟不带前缀0的分钟、mm表示0~9分钟带前缀0
        s(秒钟):s表示0~9秒钟不带前缀0的秒种、ss表示0~9秒钟带前缀0
        S(毫秒):S的个数可以连写1~9个,用来表示不同位数的毫秒。
        n(纳秒):n无法连写多个,书写一个n表示纳秒。
        A(一天中的毫秒数): A无法连写多个。
        N(一天中的纳秒数): N无法连写多个。
 
    '## 时区的一些格式化字符(得是带时区对象才行):'
        V(时区ID):书写时必须使用VV;可获取的ID如:Asia/Shanghai、GMT、UTC、Z、GMT+08:30、-08:00等。
        z(时区名称):中国区域都输出的是:CST;具体看下方的z介绍。
        O(本地化的时区偏移量):书写必须为O、OOOO格式;如"Asia/Shanghai"使用0=GMT+8、OOOO=GMT+08:00
        X(时区偏移量):X书写必须为1~5个;假设时区为:"GMT+08:20:40",按照书写X个数分别为如下展现形式:
                    +0820(若没有分钟时区则直接+08)、+0820、+08:20、+082040、+08:20:40
        x(时区偏移量):和X基本一致,区别是X表示Z(0时区)为Z;而x表示Z时区为+00
        Z(基本的时区偏移量):如在GMT+08:20:40打印设置Z=+0820、ZZZZ=GMT+08:20:40、ZZZZZ=+08:20:40
 
    '## 其它特殊格式化字符:'
        ''(字符本身):双单引号表示单引号字符本身,用于在日期时间格式中表示文字单引号。
        [,](可选择部分):被[]包裹在里面的字符格式化是存在则进行展示,不存在则自动忽略。
                        如:日期时间是不包含时区的信息,格式化字符设置的时区字符必须包含在[]内。
        #,{,}(保留字符):保留字符供将来使用。
public static void main(String[] args) {
    // 创建一个带时区的时间,通过LocalDate、LocalTime、ZoneId组装得来。
    LocalDate localDate = LocalDate.of(2024, 2, 23);
    LocalTime localTime = LocalTime.of(12, 0, 3, 9999);
    ZoneId zoneId = ZoneId.of("Asia/Shanghai");
    // 创建不带时区的日期时间:2024-02-23T12:10:30.000009999
    LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
    // 创建带时区的日期时间:2024-02-23T12:10:30.000009999+08:00[Asia/Shanghai]
    ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
    
    // 创建格式化字符信息;按照[]可以部分选择需要格式化的信息
    String str = "[yyyy-MM-dd ][HH:mm:ss:SSS][XX'['VV']']";
    DateTimeFormatter pattern = DateTimeFormatter.ofPattern(str);
    // 修改当前格式化区域,英语
    pattern = pattern.withLocale(Locale.ENGLISH);
    // 格式化日期
    System.out.println(zonedDateTime.format(pattern));// 2024-02-23 12:00:03:000+0800[Asia/Shanghai]
    System.out.println(localDateTime.format(pattern));// 2024-02-23 12:00:03:000
    System.out.println(localDate.format(pattern));    // 2024-02-23
    System.out.println(localTime.format(pattern));    // 12:00:03:000
}

(四):字符串日期转对象

  字符串转日期相对来说简单些,只要告诉 parse() 方法解析方式即可,下面就从案例中讲解。

public static void main(String[] args) {
    // 创建现在的日期时间:2024-07-26T16:10:05.524
    LocalDateTime localDateTime = LocalDateTime.now();
    // 获取当前日期时间的字符串表示形式:2024-07-26T16:10:05.524
    String ldtStr = localDateTime.toString();
    // 将日期时间字符串再转换成对应的日期时间对象:2024-07-26T16:10:05.524
    LocalDateTime parse = LocalDateTime.parse(ldtStr);
    // 上面三行代码看出,日期时间对象使用的是toString输出的默认格式时,转换成对象时无需设置格式化字符。
    // 设置自定义的日期格式化字符信息
    DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String zdyLdtStr = localDateTime.format(pattern);
    System.out.println("转成字符串zdyLdtStr:" + zdyLdtStr);
    // 转成字符串zdyLdtStr:2024-07-26 16:10:05
    // 通过指定形式的格式化字符来转会日期时间对象
    LocalDateTime parse1 = LocalDateTime.parse(zdyLdtStr, pattern);
    // LocalDateTime parse2 = LocalDateTime.parse(zdyLdtStr);报错
    System.out.println(parse1); // 2024-07-26T16:10:05
}

三:now()日期创建详解

  前面我们说过now()方法的默认创建当前日期时间对象,但是它可不止有一个默认创建日期时间的方法,细心的可以发现它还有带Clock和ZoneId参数的now方法,其实就是通过时钟或时区来创建当前日期时间,下面就说明一下用法。   其实LocalDateLocalTimeLocalDateTimeZonedDateTimeOffsetDateTime这几个类中他都会存在带Clock和ZoneId这两个参数的now方法,需要注意的是Instant类它的now方法最多只能传入Clock参数,因为Instant它创建的时刻是没有时区这一说法,所以没有通过时区创建的对象方法。

public static void main(String[] args) {
    // 它是通过系统默认的GMT+08时区来构建的日期;
    System.out.println("当前时间为:" + LocalDateTime.now()); // 当前时间为:2024-07-22T23:56:03.216
    // 创建亚洲上海的时区ID,此时区ID其实就是GMT+09:00;
    ZoneId zoneId = ZoneId.of("Asia/Tokyo");
    // 创建一个UTC时钟对象,也可以认为是GMT+00:00的时钟;
    Clock clockUTC = Clock.systemUTC();
    // ### 关于LocalDate
    System.out.println(LocalDate.now(zoneId));   // 2024-07-23
    // 说明:因为"Asia/Tokyo"它是GMT+09,而开头的时间是通过默认的GMT+08时区创建的,
    // 所以这里的日期需要在原基础上+1,一旦+1就变为第二天23号了。
    System.out.println(LocalDate.now(clockUTC)); // 2024-07-22
    // 这个就好理解了,在默认的时间上-8个小时,因为clockUTC它位于GMT+00时区上
    // ### 关于LocalTime
    System.out.println(LocalTime.now(zoneId));   // 00:56:03.217
    System.out.println(LocalTime.now(clockUTC)); // 15:56:03.217
    // 第一个打印就是在原基础上+1小时,第二个打印就是在原基础上-8小时
    // 按照上面的两个推算,那下面3个我们就可以理解了,计算一下时区就可以得出答案。
    // ### 关于LocalDateTime
    System.out.println(LocalDateTime.now(zoneId));   // 2024-07-23T00:56:03.217
    System.out.println(LocalDateTime.now(clockUTC)); // 2024-07-22T15:56:03.217
    // ### 关于ZonedDateTime
    System.out.println(ZonedDateTime.now(zoneId));  // 2024-07-23T00:56:03.217+09:00[Asia/Tokyo]
    System.out.println(ZonedDateTime.now(clockUTC));// 2024-07-22T15:56:03.217Z
    // ### 关于OffsetDateTime
    System.out.println(OffsetDateTime.now(zoneId));   // 2024-07-23T00:56:03.218+09:00
    System.out.println(OffsetDateTime.now(clockUTC)); // 2024-07-22T15:56:03.218Z
    // ### 关于Instant
    Instant instant = Instant.now(Clock.system(ZoneId.of("GMT+09:00")));
    Instant instant1 = Instant.now(clockUTC);
    System.out.println(instant.toEpochMilli());     // 1721663763218
    System.out.println(instant1.toEpochMilli());    // 1721663763218
    // 需要注意的是我们传入的Clock不管是多少的时区,最终都会转换成UTC,就是0时区来生成对象。
    // 通过Instant来生成日期时间,但是必须传时区哟,传了时区才能计算给定的Instant具体日期时间。
    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(localDateTime); // 2024-07-22T23:56:03.218
}

四:from()从指定实例获取对象

  了解前面的一些日期时间类的话,就会发现,基本上每个类都会有个static from()方法,就是告诉这个方法创建当前对象的信息来自哪个日期时间类;通常用于从其它类型转换或者创建日期时间对象。这些方法能够根据给定的信息创建或者转换成指定的日期时间对象。   在from()方法内存在 两种类型的参数,分别是 TemporalAmountTemporalAccessor ;其中TemporalAmount接口表示一段时间的量,可以是一个持续时间(Duration)或者一个日期范围(Period)。而TemporalAccessor接口是一个只读的日期时间对象,它允许读取日期时间对象的值而不会修改它们,其实现接口如LocalDateTime、ZonedDateTime等。   注意:关于Clock时钟对象里没有from()方法以外,其它日期时间对象中都存在此方法

点开查看详情:from()方法可传的参数对象
'总结:'
  '所有from()方法传入的对象参数必须要能从传入的实例中提取到需要创建的实例才行,否则一律报错。'
  '所有from()方法都可以传入调用对象自己的实例。'
  '比如:LocalDate的from()方法可以传入LocalDateTime对象实例,因为LocalDateTime中可以提取到LocalDate。'
TemporalAmount接口类型参数:
    static Period from(TemporalAmount amount)
        可接收类型:Period
    static Duration from(TemporalAmount amount)
        可接收类型:Duration
TemporalAccessor接口类型参数:
    static Year from(TemporalAccessor temporal)
        可接收类型:Year、LocalDate、LocalDateTime、ZonedDateTime、OffsetDateTime、YearMonth
    static YearMonth from(TemporalAccessor temporal)
        可接收类型:YearMonth、LocalDate、LocalDateTime、ZonedDateTime、OffsetDateTime
    static MonthDay from(TemporalAccessor temporal)
        可接收类型:LocalDate、LocalDateTime、ZonedDateTime、OffsetDateTime、MonthDay
    static LocalDate from(TemporalAccessor temporal)
        可接收类型:LocalDate、LocalDateTime、ZonedDateTime、OffsetDateTime
    static LocalTime from(TemporalAccessor temporal)
        可接收类型:LocalTime、LocalDateTime、ZonedDateTime、OffsetDateTime、OffsetTime
    static LocalDateTime from(TemporalAccessor temporal)
        可接收类型:LocalDateTime、ZonedDateTime、OffsetDateTime
    static OffsetTime from(TemporalAccessor temporal)
        可接收类型:ZonedDateTime、OffsetDateTime、OffsetTime
    static OffsetDateTime from(TemporalAccessor temporal)
        可接收类型:ZonedDateTime、OffsetDateTime
    static ZonedDateTime from(TemporalAccessor temporal)
        可接收类型:ZonedDateTime、OffsetDateTime
    static ZoneId from(TemporalAccessor temporal)
        可接收类型:ZoneOffset、ZonedDateTime、OffsetDateTime、OffsetTime
    static ZoneOffset from(TemporalAccessor temporal)
        可接收类型:ZoneOffset、ZonedDateTime、OffsetDateTime、OffsetTime
    static Instant from(TemporalAccessor temporal)
        可接收类型:Instant、ZonedDateTime、OffsetDateTime。
public static void main(String[] args) {
    LocalDate localDate = LocalDate.now();
    //      打印:2024-07-23
    LocalDateTime localDateTime = LocalDateTime.now();
    //      打印:2024-07-23T21:01:47.748
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    //      打印:2024-07-23T21:01:47.749+08:00[Asia/Shanghai]
    OffsetDateTime offsetDateTime = OffsetDateTime.now();
    //      打印:2024-07-23T21:01:47.749+08:00
    // 从 LocalDateTime 对象实例提取 LocalDate 对象实例
    System.out.println(LocalDate.from(localDateTime));      // 2024-07-23
    // 从 ZonedDateTime 对象实例提取 ZonedDateTime 对象实例
    System.out.println(ZoneId.from(zonedDateTime));         // Asia/Shanghai
    // 从 ZonedDateTime 对象实例提取 ZoneOffset 对象实例
    System.out.println(ZoneOffset.from(zonedDateTime));     // +08:00
    // 从 OffsetDateTime 对象实例提取 LocalDateTime 对象实例
    System.out.println(LocalDateTime.from(offsetDateTime)); // 2024-07-23T21:01:47.749
    // 从 LocalDate 对象实例提取 LocalTime 对象实例;报错!!;日期对象中不存在时间信息。
    // System.out.println(LocalTime.from(localDate));
    // Unable to obtain LocalTime from TemporalAccessor: 2024-07-23 of type java.time.LocalDate
}

五:query()通用日期对象查询

  在query()方法中供了一套强大且易于使用的方式来 自定义处理和查询 日期、时间、持续时间(时刻)、时区(时区偏移)等这些对象。其中query()方法需要传入 TemporalQuery<R> 类型的函数式接口参数,我们在这个函数式接口中编写自定义的方式来从日期时间对象中获取特定的信息或执行自定义的操作。若不想自己实现函数式接口的话也可以使用TemporalQueries 类实现好的部分功能,具体需要编写自定义的处理方式也可以参考这个类的写法来完成想实现的操作。   注意的是query()方法在Clock、Period、Duration、ZoneId中是没有此方法的。

'关于Java8自带的实现TemporalQuery函数式接口的TemporalQueries类说明:'
    static TemporalQuery<Chronology> chronology()
        查询当前日期时间的Chronology(历法)。返回如如:ISO、Hijrah等;它和getChronology()方法基本一样。
    static TemporalQuery<LocalDate> localDate()
        查询当前日期时间的LocalDate(日期);它和toLocalDate()方法基本一样。
    static TemporalQuery<LocalTime> localTime()
        查询当前日期时间的LocalTime(时间);它和toLocalTime()方法基本一样。
    static TemporalQuery<ZoneOffset> offset()
        查询当前日期时间的ZoneOffset(时区偏移量);它和getOffset()方法基本一样。
    static TemporalQuery<TemporalUnit> precision()
        查询当前日期时间的最小支持单位(TemporalUnit)。如LocalTime最小支持单位可以是Nanos、Seconds等。
    static TemporalQuery<ZoneId> zone()
        查询当前日期时间的ZoneId(时区标识符),如果找不到适合的ZoneId,它会回退到查询ZoneOffset。
        这意味着它可以获取时区偏移量或具体的时区标识符。
    static TemporalQuery<ZoneId> zoneId()
        严格的查询,查询当前日期时间的ZoneId(时区标识符),如果找不到适合的ZoneId,则返回null
'注意的是:上面的所有方法在转换时无法获取此对象的对应信息或无法确认最小单位时则一律返回null。'
'若是自定义实现的话需要注意以下几点:'
    下面是个示例:
        static final TemporalQuery<LocalTime> LOCAL_TIME = (temporal) -> {
            if (temporal.isSupported(NANO_OF_DAY)) {
                return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY));
            }
            return null;
        };
    temporal其实就是日期对象本身,但是无法直接使用具体的方法,因为它不知道日期类型是啥,所以只有几个通用方法。
    其中就是isSupported用来判断分量是否可以使用,能使用才可以处理具体信息,具体看示例。
public static void main(String[] args) {
    // 创建两个基本的日期时间对象
    LocalDateTime localDateTime = LocalDateTime.now();
    //      打印: 2024-07-24T15:29:38.027
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    //      打印: 2024-07-24T15:29:38.028+08:00[Asia/Shanghai]
    // 示例
    Chronology chronology = zonedDateTime.query(TemporalQueries.chronology());
    System.out.println(chronology); // ISO
    LocalDate localDate = zonedDateTime.query(TemporalQueries.localDate());
    System.out.println(localDate);  // 2024-07-24
    LocalTime localTime = zonedDateTime.query(TemporalQueries.localTime());
    System.out.println(localTime);  // 15:29:38.028
    ZoneOffset zoneOffset = zonedDateTime.query(TemporalQueries.offset());
    System.out.println(zoneOffset); // +08:00
    ZoneId zone = zonedDateTime.query(TemporalQueries.zone());
    System.out.println(zone);  // Asia/Shanghai
    ZoneId zoneId = zonedDateTime.query(TemporalQueries.zoneId());
    System.out.println(zoneId);// Asia/Shanghai
    // 自定义实现函数式接口
    // 自定义设置;校验当前的日期时间是四季中的那一季度
    TemporalQuery<String> temporalQueryQuarter = (temporal) -> {
        // 校验当前传入的日期是否可以获取年月日字段
        if (temporal.isSupported(ChronoField.YEAR)
                && temporal.isSupported(ChronoField.MONTH_OF_YEAR)
                && temporal.isSupported(ChronoField.DAY_OF_MONTH)) {
            // 都存在则转换成日期
            LocalDate ld = LocalDate.from(temporal);
            // 获取月份
            switch (ld.getMonth()) {
                case JANUARY:
                case FEBRUARY:
                case MARCH:
                    return "春季";
                case APRIL:
                case MAY:
                case JUNE:
                    return "夏季";
                case JULY:
                case AUGUST:
                case SEPTEMBER:
                    return "秋季";
                case OCTOBER:
                case NOVEMBER:
                case DECEMBER:
                    return "冬季";
            }
        }
        return null;
    };
    // 调用自定义的日期查询处理
    System.out.println("当前的季度是:" + localDateTime.query(temporalQueryQuarter));
    // 当前的季度是:秋季
}

六:adjustInto()部分替换

  可以说 adjustInto(Temporal temporal)方法 大伙并不陌生,它就是使用当前调用方法的对象中的值来将传入的对象temporal参数部分替换,从而形成一个Temporal对象返回;可能看完这句话非常绕,其实也很简单,举个例子,比如LocalTime对象实例调用了adjustInto()方法并且传了一个LocalDateTime对象实例,那么LocalTime就会替换掉LocalDateTime里的时间(LocalTime)部分。   注意这些类是没有此方法:Clock、Period、Duration、ZonedDateTime、ZoneId。

public static void main(String[] args) {
    // 创建一些基本的对象供下面案例使用。
    // 创建默认的日期时间对象:2024-07-25T11:09:28.015
    LocalDateTime localDateTime = LocalDateTime.now();
    // 创建时间对象:12:15:30
    LocalTime localTime = LocalTime.of(12, 15, 30);
    // 将localTime值替换到localDateTime中
    Temporal temporal = localTime.adjustInto(localDateTime);
    System.out.println(temporal); // 2024-07-25T12:15:30
    // 转换成LocalDateTime对象;转换之前一定要确认是可以转换
    LocalDateTime ldt = LocalDateTime.from(temporal);
    System.out.println(ldt); // 2024-07-25T12:15:30
}
转载自:https://juejin.cn/post/7396332696661147657
评论
请登录