问题描述
问题:输入时间戳、时区,返回一个带时区的时间字符串?
代码如下:
long timestamp = 1647489600000L; // 2022-03-15 12:00:00 Asia/Shanghai String timeZoneName = "America/New_York"; Instant instant = Instant.ofEpochMilli(timestamp); ZonedDateTime zonedDateTime = ZonedDateTime.of(LocalDateTime.ofInstant(instant, ZoneId.systemDefault()), TimeZone.getTimeZone(timeZoneName).toZoneId()); System.out.println(zonedDateTime); ZonedDateTime zonedDateTime1 = ZonedDateTime.of(LocalDateTime.ofInstant(instant, ZoneId.systemDefault()), TimeZone.getTimeZone("Asia/Shanghai").toZoneId()); System.out.println(zonedDateTime1);
输出结果如下:
几个类简单说明一下:
Instant
可以将时间戳转换为本地日期/时间LocalDateTime
。
- 在
JDK 8
之前,Java使用java.util.TimeZone
来表示时区。而在JDK 8里分别使用了ZoneId
表示时区,ZoneOffset
表示UTC
的偏移量。
ZonedDateTime
是一个带时区的日期类。
夏令时(DST)
我们知道,纽约是 西五区
,上海是 东八区
那么应该和我们的时间相差13 个小时(因为一个时区就是相差一个小时),但是我们得到的结论,确实是相差了 12 个小时,是不是有点怀疑自己。
再来看看,居然是 11 点,明明是相差 12 个小时,为什么说是比北京时间慢 14 小时这就是由于当前时间是夏令时导致的。
一个特殊的例子:
ZonedDateTime zonedDateTime2 = ZonedDateTime.ofInstant(instant, TimeZone.getTimeZone("GMT-05:00").toZoneId()); System.out.println(zonedDateTime2); // 结果:2022-03-16T23:00-05:00[GMT-05:00]
如果我们使用 GMT-05:00
来获取时区的时间,那么就不会触发夏令时,可能会和你想象的结果不同。
换句话说 America/New_York
可能是 GMT-05:00
也可能是 GMT-04:00
这个具体要看 LocalDateTime
是否在夏令时的时间区间内.
如何通过 America/New_York
获取到 GMT-xx
一个简单的方法
ZonedDateTime of = ZonedDateTime.of(LocalDateTime.now(ZoneId.of("America/New_York")), ZoneId.of("America/New_York")); System.out.println(of.getOffset().getId());
输出:
-04:00
思路来源于
说明一下:
ZonedDateTime 包括 LocalDateTime 和 ZoneId 我们将 -04:00
加上 GTM 前缀就可以了,而且已经包含夏令时的处理。
总结一下
1、如果按照用户侧,百度上的时间来算,由于现在是夏令时,所以 America/New_York
方式的时区才能正确的获取本地时间。
2、 具体的 Java 几个日期类的差别,大家可以看看参考资料中的文件。
3、 对于时区,时间戳,夏令时来说,相互转换有时候特别容易混淆。