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

日期时间格式化及转换

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

(一):快速入门

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

java

代码解读

复制代码

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 }

整理了一份Java八股文笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记【点击此处】即可免费获取

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

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

点开查看详情:DateTimeFormatter自带的格式化器

java

代码解读

复制代码

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中使用的格式化字符说明

java

代码解读

复制代码

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() 方法解析方式即可,下面就从案例中讲解。

 

java

代码解读

复制代码

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它创建的时刻是没有时区这一说法,所以没有通过时区创建的对象方法。

 

java

代码解读

复制代码

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()方法内存在 两种类型的参数,分别是 TemporalAmount 和 TemporalAccessor ;其中TemporalAmount接口表示一段时间的量,可以是一个持续时间(Duration)或者一个日期范围(Period)。而TemporalAccessor接口是一个只读的日期时间对象,它允许读取日期时间对象的值而不会修改它们,其实现接口如LocalDateTime、ZonedDateTime等。
  注意:关于Clock时钟对象里没有from()方法以外,其它日期时间对象中都存在此方法

点开查看详情:from()方法可传的参数对象

 
 

java

代码解读

复制代码

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中是没有此方法的。

 

java

代码解读

复制代码

'关于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用来判断分量是否可以使用,能使用才可以处理具体信息,具体看示例。

 

java

代码解读

复制代码

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。

 

java

代码解读

复制代码

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 }

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值