Java8时区时间运用详解,2万字助你通关java.time包
转换核心思路
各种时间类的转换核心只有一个流程:时间类 -> 时间戳 -> 时间类
- Date和Instant它们存储的都是时间戳信息
- LocalDateTime、LocalDate、LocalTime、ZonedDateTime、OffsetDateTime、OffsetTime、Year等其它Java8时间类则是
年、月、日、时、分、秒、纳秒
中的部分值 + 时区或偏移量的组合
从转换角度来说,Date可以直接转为Instant,也可以根据时间戳直接转为其它时间类;Java8的其它时间类之间可以相互转换,也可以转为时间戳再转为Date或Instant。
所以本文有5种思路进行时间转换:
- Date转Instant
- Instant转Date
- Date转java8其它时间类
- Java8其它时间类转Date
- Java8的时间类互转
时间转换
1. Date —》 Instant
Date内部使用long fastTime
存储整个时间戳System.currentTimeMillis()
,而Instant则是使用秒long seconds
和纳秒int nanos
存储整个时间戳。所以它们可以直接互转。这里有一点要注意,时间戳记录的是UTC+0或GMT+0的时间,直接输出Date.toString()
时,实际上会自动将GMT+0时间转为系统默认时区时间。
Date date = new Date();
// 1. Date兼容了Instant,可以直接转
Instant instant = date.toInstant();
// 2. 或通过时间戳初始化
Instant.ofEpochMilli(date.getTime());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// SimpleDateFormat中使用当前系统的默认时区输出时间,所以需要把时区转为UTC时区才能保证两者区时一致
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(simpleDateFormat.format(date));
System.out.println(instant);
输出时间:
2023-04-25 05:52:43
2023-04-25T05:52:43.246Z
2. Instant —》 Date
Instant与Date的互转方法类似,都是通过时间戳来创建实例:
Instant instant = Instant.now();
// 1. 构造方法转换
Date date = Date.from(instant);
// 2. 通过时间戳初始化
new Date(instant.toEpochMilli());
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(simpleDateFormat.format(date));
System.out.println(instant);
输出时间:
2023-04-25 06:05:00
2023-04-25T06:05:00.882Z
3. Date —》 java8时间类
A. 通过转Instant的方式实现转换时间类
下面的时区ZoneId
和时间偏移量ZoneOffset
可以修改为系统的默认时区ZoneId.systemDefault()
以显示和new Date().toString()
一样的本地时间。
Date date = new Date();
Instant instant = date.toInstant();
// 1. 通过添加时区、偏移量信息直接转换
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("UTC"));
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
// 2. 通过构造方法
ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"));
OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
B. 通过时间戳转时间类
正如一开始提到的核心转换思路,我们可以提供Date的时间戳(Instant同理),再将时间戳转为其它时间类:
long timestamp = date.getTime();
// 这里的计算就是Date转Instant,Instant转LocalDateTime的源代码实现方式
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(Math.floorDiv(timestamp, 1000),
(int) Math.floorMod(timestamp, 1000), ZoneOffset.UTC);
// 然后通过LocalDateTime转其它类
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();
ZonedDateTime zonedDateTime1 = localDateTime.atZone(ZoneId.of("UTC"));
OffsetDateTime offsetDateTime1 = localDateTime.atOffset(ZoneOffset.UTC);
C. 通过字符串格式化转换
这种方式比较取巧,不过却很有用,需要注意的点是:LocalDateTime、ZonedDateTime和OffsetDateTime必须提供偏移量信息(或时区信息)。
String pattern = "yyyy-MM-dd HH:mm:ss X";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String format = simpleDateFormat.format(date);
LocalDateTime.parse(format, dateTimeFormatter);
OffsetDateTime.parse(format, dateTimeFormatter);
ZonedDateTime.parse(format, dateTimeFormatter);
DateTimeFormatter中关于时间格式化中字母代表的匹配含义(部分):
- V:时区ID,America/Los_Angeles; Z; -08:30
- z:时区名称或简称, Pacific Standard Time; PST
- Z:时间偏移量,无指定时区,仅代表偏移量范围,+0000; -0800; -08:00;
- x:时间偏移量,无指定时区,仅代表偏移量范围,+0000; -08; -0830; -08:30; -083015; -08:30:15;
- X:世界时(UTC-GMT-UT,取决于时间类支持哪一个世界时)的时间偏移量,Z; -08; -0830; -08:30; -083015; -08:30:15;
- O:带时区的时间偏移量,GMT+8; GMT+08:00; UTC-08:00;
SimpleDateFormat中关于时间格式化中字母代表的匹配含义(部分):
- V:无
- z:时区名称或简称或时区偏移量, Pacific Standard Time; PST;GMT-08:00
- Z:时间偏移量,无指定时区,仅代表偏移量范围,+0000; -0800; -08:00;
- x:无
- X:时间偏移量,无指定时区,仅代表偏移量范围,-08; -0800; -08:00
- O:无
对比上述三种方法可以看到,Date要转其它时间类,还是通过先转Instant -> 再转其它时间类的方式更方便。
4. Java8时间类 —》 Date
使用Date转java8其它时间类的逆方向转换即可。
初始化时间:
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now();
A. 通过转Instant的方式实现转换Date
转Instant,再转Date
Instant instant = localDateTime.toInstant(ZoneOffset.ofHours(8));
offsetDateTime.toInstant();
zonedDateTime.toInstant();
Date date = Date.from(instant);
// 输出
System.out.println(localDateTime);
System.out.println(offsetDateTime);
System.out.println(zonedDateTime);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
输出时间:
2023-04-25T15:18:53.585
2023-04-25T15:18:53.586+08:00
2023-04-25T15:18:53.586+08:00[Asia/Shanghai]
2023-04-25 15:18:53
B. 通过时间戳转Date
localDateTime等时间类可以获取时间的秒级时间戳,所以可以根据这个时间戳直接转为Date。这种转换会损失纳毫秒精度,如果对精度有要求的话,还是得通过转Instant然后调用方法toEpochMilli()
来实现。
long epochSecond = localDateTime.toEpochSecond(ZoneOffset.ofHours(8));
offsetDateTime.toEpochSecond();
zonedDateTime.toEpochSecond();
Date date1 = new Date(epochSecond * 1000L);
C. 通过字符串格式化转换
由于Java8中的时间类具备不同的属性(时区、偏移量等),所以通过时间字符串格式化时,LocalDateTime、OffsetDateTime和ZonedDateTime的格式化字符串有所不同。这一点与Date转这些时间类不同,需要在实际转换时注意。
String local = "yyyy-MM-dd HH:mm:ss";
String offset = "yyyy-MM-dd HH:mm:ss X";
String zone = "yyyy-MM-dd HH:mm:ss z";
System.out.println(new SimpleDateFormat(local).parse(DateTimeFormatter.ofPattern(local).format(localDateTime)));
System.out.println(new SimpleDateFormat(offset).parse(DateTimeFormatter.ofPattern(offset).format(offsetDateTime)));
System.out.println(new SimpleDateFormat(zone).parse(DateTimeFormatter.ofPattern(zone).format(zonedDateTime)));
输出时间如下:
Tue Apr 25 16:18:37 CST 2023
Tue Apr 25 16:18:37 CST 2023
Tue Apr 25 16:18:37 CST 2023
5. Java8时间类互转
下面的转换将会提供每一种时间类支持的所有转换情况,包括构造方法、实例对象方法。
A. Instant
Instant instant = Instant.now();
// 通过实例对象转换
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("UTC"));
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
// 通过构造方法转换
ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"));
OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
B. LocalDateTime
转换OffsetDateTime和ZonedDateTime时,没有toXX
方法、且不能使用from(TemporalAccessor temporal)
构造方法实例化,因为LocalDateTime没有时区和偏移量信息。
LocalDateTime localDateTime = LocalDateTime.now();
ZoneOffset zoneOffset = ZoneOffset.ofHours(8);
// 通过实例对象转换
Instant instant = localDateTime.toInstant(zoneOffset);
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneOffset);
OffsetDateTime offsetDateTime = localDateTime.atOffset(zoneOffset);
// 通过构造方法转换
Instant.ofEpochSecond(localDateTime.toEpochSecond(zoneOffset));
LocalDate.from(localDateTime);
LocalTime.from(localDateTime);
OffsetDateTime.of(localDateTime, zoneOffset);
ZonedDateTime.of(localDateTime, zoneOffset);
C. OffsetDateTime
OffsetDateTime和ZonedDateTime的转换相同,使用toXXX
直接转为其它时间类,使用其它时间类的from
方法复制其时间信息。文章来源:https://www.toymoban.com/news/detail-430702.html
OffsetDateTime offsetDateTime = OffsetDateTime.now();
// 通过实例对象转换
Instant instant = offsetDateTime.toInstant();
OffsetTime offsetTime = offsetDateTime.toOffsetTime();
LocalDate localDate = offsetDateTime.toLocalDate();
LocalTime localTime = offsetDateTime.toLocalTime();
LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();
// 通过构造方法转换
Instant.from(offsetDateTime);
OffsetTime.from(offsetDateTime);
LocalDate.from(offsetDateTime);
LocalTime.from(offsetDateTime);
LocalDateTime.from(offsetDateTime);
ZonedDateTime.from(offsetDateTime);
D.ZonedDateTime文章来源地址https://www.toymoban.com/news/detail-430702.html
ZonedDateTime zonedDateTime = ZonedDateTime.now();
// 通过实例对象转换
Instant instant = zonedDateTime.toInstant();
LocalDate localDate = zonedDateTime.toLocalDate();
LocalTime localTime = zonedDateTime.toLocalTime();
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime();
// 通过构造方法转换
Instant.from(zonedDateTime);
OffsetTime.from(zonedDateTime);
OffsetDateTime.from(zonedDateTime);
LocalDate.from(zonedDateTime);
LocalTime.from(zonedDateTime);
LocalDateTime.from(zonedDateTime);
到了这里,关于Java8 掌握Date与Java.time转换的核心思路,轻松解决各种时间转换问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!