一文搞懂Java8中表示当前的时间类Date、Instant、LocalDateTime、ZonedDateTime

一文搞懂Java8中表示当前的时间类Date、Instant、LocalDateTime、ZonedDateTime1 概述 Java8 中的时间类主要有 Date Instant LocalDateTim LocalDate LocalTime ZonedDateTim 除去 Date java time 包下的那些时间类都是不可变类 也就是说 其是线程安全的 对其设置只会产生一个新对象

大家好,我是讯享网,很高兴认识大家。

1. 概述

Java8中的时间类主要有:Date、Instant、LocalDateTime(LocalDate、LocalTime)、ZonedDateTime,除去Date,java.time包下的那些时间类都是不可变类,也就是说:其是线程安全的,对其设置只会产生一个新对象。

在这里,我们要分清楚包含时区信息的类、以及不包含时区信息的类。不包含时区信息的类实际上就类似于一个yyyy-MM-dd HH:mm:ss字符串,需要额外的时区信息才能表达一个时刻,即LocalDateTime、LocalDate、LocalTime。而Date(0时区)、Instant(0时区)、ZonedDateTime都包含有时区信息。

import java.util.Date; import java.util.TimeZone; class Scratch { 
    public static void main(String[] args) { 
    TimeZone.setDefault(TimeZone.getTimeZone("GMT")); Date d1 = new Date(); Instant i1 = Instant.now(); ZonedDateTime z1 = ZonedDateTime.now(); LocalDateTime l1 = LocalDateTime.now(); TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); Date d2 = new Date(); Instant i2 = Instant.now(); ZonedDateTime z2 = ZonedDateTime.now(); LocalDateTime l2 = LocalDateTime.now(); TimeZone.setDefault(TimeZone.getTimeZone("Australia/Darwin")); Date d3 = new Date(); Instant i3 = Instant.now(); ZonedDateTime z3 = ZonedDateTime.now(); LocalDateTime l3 = LocalDateTime.now(); } } 

讯享网

断点变量图
讯享网
看懂上面的代码以及断点处的变量图基本就搞懂了Java8中的时间类的使用了。我劝你可千万别跳过,好好看看。

2. 类结构

2.1. Date

讯享网 private transient long fastTime; private transient BaseCalendar.Date cdate; 

本质是记录了0时区的时间,不同时区的人在同一时刻new Date()时,其对象内存放的毫秒数是一样的(都是0时区)。

2.1.1. 转换成字符串

因为System.out.println函数在打印时间时,会取操作系统当前所设置的时区,然后根据这个时区将毫秒数解释成该时区的时间。或是SimpleDateTimeFormat这种日期格式化类也会在打印时根据时区解释Date中的毫秒数。

Date date = new Date(00L); // 对应的北京时间是2017-08-24 11:17:10 SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 北京 bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设置北京时区 SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 东京 tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); // 设置东京时区 SimpleDateFormat londonSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 伦敦 londonSdf.setTimeZone(TimeZone.getTimeZone("Europe/London")); // 设置伦敦时区 System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date)); System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date)); System.out.println("毫秒数:" + date.getTime() + ", 伦敦时间:" + londonSdf.format(date)); // 输出 // 毫秒数:00, 北京时间:2017-08-24 11:17:10 // 毫秒数:00, 东京时间:2017-08-24 12:17:10 // 毫秒数:00, 伦敦时间:2017-08-24 04:17:10 

2.1.2. 从字符串中读取时间

2017-8-24 11:17:10解析为一个Date对象,会根据SimpleDateFormat设置的时区而将其转换成0时区的Date对象。将一个时间字符串按不同时区来解释,得到的Date对象的值是不同的。验证如下:

讯享网String timeStr = "2017-8-24 11:17:10"; // 字面时间 SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); Date bjDate = bjSdf.parse(timeStr); // 解析 System.out.println("字面时间: " + timeStr +",按北京时间来解释:" + bjSdf.format(bjDate) + ", " + bjDate.getTime()); SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 东京 tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); // 设置东京时区 Date tokyoDate = tokyoSdf.parse(timeStr); // 解析 System.out.println("字面时间: " + timeStr +",按东京时间来解释:" + tokyoSdf.format(tokyoDate) + ", " + tokyoDate.getTime()); // 输出为: // 字面时间: 2017-8-24 11:17:10,按北京时间来解释:2017-08-24 11:17:10, 00 // 字面时间: 2017-8-24 11:17:10,按东京时间来解释:2017-08-24 11:17:10, 00 

2.2. Instant

 private final long seconds; private final int nanos; 

本质是记录了0时区的时间

2.3. LocalDateTime、LocalDate、LocalTime

根据当前设置的时区获取当前时区的日期、时间,但不会记录时区信息。

Local*这些时间类实际上就相当于一个字符串,只不过把年月日、时分秒解析出来了而已。
String与LocalDateTime是等价的

2.3.1. LocalDateTime:

讯享网 private final LocalDate date; private final LocalTime time; 

2.3.2. LocalDate:

 private final int year; private final short month; private final short day; 

2.3.3. LocalTime

讯享网 private final byte hour; private final byte minute; private final byte second; private final int nano; 

2.4. ZonedDateTime

在LocalDateTime的基础上同时保存了当前的时区,即:根据当前设置的时区获取当前时区的日期、时间,同时保存当前时区信息。

 private final LocalDateTime dateTime; private final ZoneOffset offset; private final ZoneId zone; 

自带时区信息,默认获取当前时区。

3. 记录时间原理

new Date()Instant.now本质上都是记录了0时区的时间,即使当前时区不同,其存储的都是距离1970-01-01 00:00:00所经过的时间。

Local*这些时间类实际上就相当于一个字符串,只不过把年月日、时分秒解析出来了而已。

4. 打印时间

打印时设置的时区信息会对原时间解析出来的字符串有影响,打印过程会转换原时区时间到现在时区时间,这点一定要注意。

Instant打印时要给DateTimeFormatter设置时区才能打印,否则会报错。

讯享网DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.of("Asia/Shanghai")) 

5. 注意点

5.1. DateTimeFormatter.with*()会返回一个新的对象

正确的做法:

DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withZone(ZoneId.of("GMT")).withLocale(Locale.UK) 

错误的做法

讯享网DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL); formatter.withZone(ZoneId.of("GMT")); formatter.withLocale(Locale.UK); 

因为DateTimeFormatter是一个不可变类,所以不可以修改其属性,同时也就是个线程安全类了。其灵活的创建过程是利用DateTimeFormatterBuilder来实现的。

5.2. DateTimeFormatter.ofPattern()没有设置打印时的时区

需要设置时区需要DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”).withZone(ZoneId.of(“GMT”))这样设置。

5.3. SimpleDateFormat并非线程安全

其format()与parse()方法都不是线程安全。

6. 拓展

6.1. Clock类

Clock是带有时区信息的时间处理类,用它可以获取不同时区的时间,也可以配合Duration,对时间进行时、分、秒级别的修改

6.2. Duration 和 Period

Duration 和 Period 都是用来表示两个时间量之间的差值,不同点在于Duration 是基于时间值,而 Period 是基于日期值。

6.3. java.time包下的5个包组成:

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

6.4. JDBC映射

最新JDBC映射将把数据库的日期类型和Java 8的新类型关联起来:

date -> LocalDate time -> LocalTime timestamp -> LocalDateTime 

6.5. SimpleDateFormat

SimpleDateFormat只能格式化Date。而DateTimeFormatter可以格式化TemporalAccessor(不包括Date,但是包括LocalDate*、Instant、ZonedDateTime等)。

7. 参考资料

  1. java 8的java.time包(非常值得推荐) - 不姓马的小马哥 - 简书
  2. Java中的时间与时区 - frcoder - CSDN
  3. 深入学习 Java 8 全新日期时间库 java.time(一)- FXBStudy - CSDN
小讯
上一篇 2025-01-24 18:01
下一篇 2025-01-07 13:24

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/122650.html