记录一次时间戳、夏令时、时区线上问题分析

简介: 记录一次时间戳、夏令时、时区线上问题分析

问题描述


问题:输入时间戳、时区,返回一个带时区的时间字符串?


代码如下:


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);


输出结果如下:


image.png


几个类简单说明一下:


  • Instant 可以将时间戳转换为本地日期/时间 LocalDateTime


  • JDK 8 之前,Java使用 java.util.TimeZone 来表示时区。而在JDK 8里分别使用了 ZoneId 表示时区,ZoneOffset 表示 UTC 的偏移量。


  • ZonedDateTime 是一个带时区的日期类。


夏令时(DST)


我们知道,纽约是 西五区,上海是 东八区  那么应该和我们的时间相差13 个小时(因为一个时区就是相差一个小时),但是我们得到的结论,确实是相差了 12 个小时,是不是有点怀疑自己。


image.png


再来看看,居然是 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


思路来源于


image.png


说明一下:


ZonedDateTime 包括 LocalDateTimeZoneId 我们将 -04:00 加上 GTM 前缀就可以了,而且已经包含夏令时的处理。


总结一下


1、如果按照用户侧,百度上的时间来算,由于现在是夏令时,所以 America/New_York 方式的时区才能正确的获取本地时间。


2、 具体的 Java 几个日期类的差别,大家可以看看参考资料中的文件。


3、 对于时区,时间戳,夏令时来说,相互转换有时候特别容易混淆。


参考资料




相关文章
|
NoSQL 安全 调度
【📕分布式锁通关指南 10】源码剖析redisson之MultiLock的实现
Redisson 的 MultiLock 是一种分布式锁实现,支持对多个独立的 RLock 同时加锁或解锁。它通过“整锁整放”机制确保所有锁要么全部加锁成功,要么完全回滚,避免状态不一致。适用于跨多个 Redis 实例或节点的场景,如分布式任务调度。其核心逻辑基于遍历加锁列表,失败时自动释放已获取的锁,保证原子性。解锁时亦逐一操作,降低死锁风险。MultiLock 不依赖 Lua 脚本,而是封装多锁协调,满足高一致性需求的业务场景。
283 0
【📕分布式锁通关指南 10】源码剖析redisson之MultiLock的实现
|
Kubernetes 负载均衡 网络协议
在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
|
SQL Java 数据库连接
Hibernate 批量操作来袭!掌握最佳实践,轻松应对数据洪流,开启高效开发新时代
【9月更文挑战第3天】在软件开发中,高效数据操作至关重要。作为流行的Java持久化框架,Hibernate提供了强大的数据库操作功能。本文探讨了Hibernate批量操作,包括批量插入、更新和删除的最佳实践,通过使用原生SQL和`Session`的`createNativeQuery()`方法,结合`addBatch()`及`executeBatch()`方法实现高效批量操作。合理设置批量大小、事务管理和性能测试是优化的关键。在实际开发中,应根据业务需求和性能要求选择合适的方法,以提升程序性能和可维护性。
854 3
|
JavaScript 前端开发 Go
一文彻底掌握Go语言运算符优先级秘密
一文彻底掌握Go语言运算符优先级秘密
407 0
|
关系型数据库 MySQL OLAP
PolarDB +AnalyticDB Zero-ETL :免费同步数据到ADB,享受数据流通新体验
Zero-ETL是阿里云瑶池数据库提供的服务,旨在简化传统ETL流程的复杂性和成本,提高数据实时性。降低数据同步成本,允许用户快速在AnalyticDB中对PolarDB数据进行分析,降低了30%的数据接入成本,提升了60%的建仓效率。 Zero-ETL特性包括免费的PolarDB MySQL联邦分析和PolarDB-X元数据自动同步,提供一体化的事务处理和数据分析,并能整合多个数据源。用户只需简单配置即可实现数据同步和实时分析。
|
XML 安全 Java
走进Java接口测试之测试框架TestNG
TestNG 是一个受 JUnit 和 NUnit 启发的测试框架,旨在简化广泛的测试需求,从单元测试到接口测试。但引入了一些新功能,使其更强大,更易于使用。
2471 1
走进Java接口测试之测试框架TestNG
|
关系型数据库 MySQL 数据库
【条理清晰】在 Windows 上安装 MySQL
【条理清晰】在 Windows 上安装 MySQL
|
JavaScript
vue 一键复制vue-clipboard2
vue 一键复制vue-clipboard2
166 0
|
安全 JavaScript PHP
URL百分号编码
URL百分号编码
|
缓存 分布式计算 数据可视化
Spring Boot + URule规则引擎,太顶了!
前段时间,在做项目重构的时候,遇到很多地方需要做很多的条件判断。当然可以用很多的if-else判断去解决,但是当时也不清楚怎么回事,就想玩点别的。于是乎,就去调研了规则引擎。 当然,市面上有很多成熟的规则引擎,功能很多,性能很好。但是,就是想玩点不一样的(大家做技术选型别这样,这个是反面教材)。最终一款URule的规则引擎吸引了我,主要还是采用浏览器可直接配置,不需要过多安装,可视化规则也做的不错。经过一系列调研,后面就把它接入了项目中,顺便记录下调研的结果。
Spring Boot + URule规则引擎,太顶了!