java.time 时区详解

news2024/11/27 17:43:17

from: https://blog.zhjh.top/archives/MFTOJ-jorm4ISK9KXEYFE

LocalDateTime 类是不包含时区信息的,可以通过 atZone 方法来设置 ZoneId,返回 ZonedDateTime 类实例,通过 atOffset 方法来设置 ZoneOffset,返回 OffsetDateTime 类实例。

ZonedDateTime 类注释详解

我们来逐段解读一下 ZonedDateTime 类的注释。

A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.

ISO-8601 日历系统中带时区的日期时间,例如 2007-12-03T10:15:30+01:00 Europe/Paris

ISO-8601 我们简单理解为是规定日期和时间如何表示的标准即可,此处不深入研究。

2007-12-03T10:15:30+01:00 Europe/Paris 中,2007-12-03 为年月日;T 是日期和时间组合表示时的固定写法,用于分隔;10:15:30 是小时分钟秒;+01:00 是此日期时间与 UTC 的时差为 +1 小时,即时区偏移(ZoneOffset)Europe/Paris 是指此日期时间的所在区域为欧洲/巴黎,即时区 ID(ZoneId),time-zone ID 请查看:List of tz database time zones。

ZonedDateTime is an immutable representation of a date-time with a time-zone. This class stores all date and time fields, to a precision of nanoseconds, and a time-zone, with a zone offset used to handle ambiguous local date-times. For example, the value “2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone” can be stored in a ZonedDateTime.

ZonedDateTime 是带时区的日期时间的常量表示。此类存储所有的日期时间(精确到纳秒)和时区,其中时区偏移用于处理不明确的本地日期时间。 例如,值 “2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone” 可以被存储在 ZonedDateTime 中。

说它是常量是因为此类是被 final 修饰的,调用它的方法时,返回的都是新实例

“时区偏移用于处理不明确的本地日期时间”,之所以不明确,是因为夏令时的存在,同一地区,不同月份,甚至不同年份的 ZoneOffset 可能不一样。详见时区信息数据库。

LocalDateTime localDateTime = LocalDateTime.of(2022, 1, 1, 0, 0);
// 设置时区 ID 为 美国/纽约
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("America/New_York"));
// 输出为 -05:00
System.out.println(zonedDateTime.getOffset());

// 设置月份为 4 月,即夏令时
zonedDateTime = zonedDateTime.withMonth(4);
// 输出为 -04:00
System.out.println(zonedDateTime.getOffset());

This class handles conversion from the local time-line of LocalDateTime to the instant time-line of Instant. The difference between the two time-lines is the offset from UTC/Greenwich, represented by a ZoneOffset.

此类处理 LocalDateTime 的本地时间线到 Instant 的瞬时时间线。两条时间线的差异是与 UTC/Greenwich 的偏移量,由 ZoneOffset 表示。

Instant(瞬时) 简单来说就是 java.time 中的时间戳(精度为纳秒),不包含时区信息。

此处说 “两条时间线的差异是与 UTC/Greenwich 的偏移量” 是指 Instant 加上 ZoneOffset 就可以获取 LocalDateTime。但如果是要将 Instant 转换为 ZonedDateTime 的话,需要设置 ZoneId。

Instant instant = Instant.now();
LocalDateTime localDateTime = instant.atOffset(ZoneOffset.ofHours(8)).toLocalDateTime();
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());

Converting between the two time-lines involves calculating the offset using the rules accessed from the ZoneId. Obtaining the offset for an instant is simple, as there is exactly one valid offset for each instant. By contrast, obtaining the offset for a local date-time is not straightforward. There are three cases:

  • Normal, with one valid offset. For the vast majority of the year, the normal case applies, where there is a single valid offset for the local date-time.
  • Gap, with zero valid offsets. This is when clocks jump forward typically due to the spring daylight savings change from “winter” to “summer”. In a gap there are local date-time values with no valid offset.
  • Overlap, with two valid offsets. This is when clocks are set back typically due to the autumn daylight savings change from “summer” to “winter”. In an overlap there are local date-time values with two valid offsets.

两条时间线之间的转换涉及到使用 ZoneId 访问规则(ZoneRules)计算偏移量。获取一个 instant 的偏移量很简单,因为每个 instant 正好有一个有效偏移量。相比之下,获取一个 local date-time 的有效偏移量
并不简单。有三种情况:

  • 正常:有一个有效的偏移量。在一年中的绝大多数时间里,local date-time 有一个有效的偏移量。
  • 间隙:没有有效的偏移量。这是由于春季夏令时从 “冬季” 到 “夏季”,时钟被调快了,跳过了一段时间。在跳过的间隙中,有 local date-time,但没有有效的偏移量。
  • 重叠:有两个有效的偏移量。这是由于秋季夏令时从 “夏季” 到 “冬季”,时钟往回调了一段时间。在重叠的情况下,有两个有效的偏移量的 local date-time。

Any method that converts directly or implicitly from a local date-time to an instant by obtaining the offset has the potential to be complicated.

For Gaps, the general strategy is that if the local date-time falls in the middle of a Gap, then the resulting zoned date-time will have a local date-time shifted forwards by the length of the Gap, resulting in a date-time in the later offset, typically “summer” time.

For Overlaps, the general strategy is that if the local date-time falls in the middle of an Overlap, then the previous offset will be retained. If there is no previous offset, or the previous offset is invalid, then the earlier offset is used, typically “summer” time… Two additional methods, withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap(), help manage the case of an overlap.

任何通过获取偏移量显式或隐式地将 local date-time 转换为 instant 地方都有可能变得复杂。

对于间隙,一般策略是,如果 local date-time 落在间隙中间,那么产生的 zoned date-time 是 local date-time 向前移动间歇的长度后的,导致日期在较晚的偏移量,通常是 “夏季” 时间。

对于重叠,一般策略是,如果 local date-time 落在重叠中间,那么以前的偏移量将被保留。如果以前没有偏移量,或者以前的偏移量无效,那么就使用较早的偏移量,通常是 “夏季” 时间。两个额外的方法,withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap(),可以帮助管理重合的情况。

In terms of design, this class should be viewed primarily as the combination of a LocalDateTime and a ZoneId. The ZoneOffset is a vital, but secondary, piece of information, used to ensure that the class represents an instant, especially during a daylight savings overlap.

就设计而言,这个类应该主要被看作是 LocalDateTimeZoneId 的组合。ZoneOffset 是一个重要但次要的信息,用来确保这个类代表一个瞬间,特别是在夏令时重叠的时候。

此处举例,美国夏令时一般在 3 月第二个周日 2AM 开始,将时钟拨快 1 小时,调到 3 点,那这一小时就是“冬季”到“夏季”的 间隙(Gap);在 11 月第一个周日 2AM,又会将时钟拨慢 1 小时,调回到 1 点,那这一小时就是“夏季”到“冬季”的 重叠(Overlap)

ZoneId zoneId = ZoneId.of("America/New_York");
ZoneRules zoneRules = zoneId.getRules();
// 美国/纽约 2022 年的夏令时间歇时间为 03-13 02:00 ~ 03:00(不包含 03:00)
LocalDateTime localDateTime = LocalDateTime.of(2022, 3, 13, 2, 30);
ZoneOffsetTransition zoneRulesTransition = zoneRules.getTransition(localDateTime);
System.out.println(zoneRulesTransition);
System.out.println(zoneRules.getTransition(localDateTime.plusMinutes(30)));
// 如果时间落在间歇中间,那对应的 zoned date-time 会加上间歇长度(此处为 1 小时),同时时区偏移量为夏令时偏移量。
System.out.println(localDateTime.atZone(zoneId));

// 输出结果为:
Transition[Gap at 2022-03-13T02:00-05:00 to -04:00]
null
2022-03-13T03:30-04:00[America/New_York]

说 “间歇没有有效的偏移量”,是因为落在间歇再转换为 zoned date-time 后,会自动加上间歇长度,所以那段时间只有 local date-time,没有偏移量。

ZoneId zoneId = ZoneId.of("America/New_York");
ZoneRules zoneRules = zoneId.getRules();
// 美国/纽约 2022 年的夏令时重叠时间为 11-06 01:00 ~ 02:00(不包含 02:00)
LocalDateTime localDateTime = LocalDateTime.of(2022, 11, 6, 1, 30);
ZoneOffsetTransition zoneRulesTransition = zoneRules.getTransition(localDateTime);
System.out.println(zoneRulesTransition);
System.out.println(zoneRules.getTransition(localDateTime.plusMinutes(30)));
// 如果时间落在重叠中间,以前没有偏移量或者以前的偏移量无效时,会使用较早的偏移量,即夏令时偏移量 -04:00
System.out.println(localDateTime.atZone(zoneId));
// 如果时间落在重叠中间,以前有偏移量且更晚时,会使用较晚的偏移量,即非夏令时偏移量 -05:00
System.out.println(localDateTime.atOffset(ZoneOffset.ofHours(-6)).atZoneSameInstant(zoneId));

// 输出结果为:
Transition[Overlap at 2022-11-06T02:00-04:00 to -05:00]
null
2022-11-06T01:30-04:00[America/New_York]
2022-11-06T02:30-05:00[America/New_York]

说 “重叠有两个有效的偏移量”,是因为落在重叠时,如果以前没有偏移量或者以前的偏移量无效时,会使用较早的偏移量;如果以前有偏移量且更晚时,会使用较晚的偏移量。

This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of ZonedDateTime may have unpredictable results and should be avoided. The equals method should be used for comparisons.

这是一个 value-based 类;在 ZonedDateTime 的实例上使用 identity-sensitive 的操作(包括引用相等 ==、identity hash code 或同步 synchronization)可能会产生不可预测的结果,所以要避免。应该使用 equals 方法来进行比较。

A ZonedDateTime holds state equivalent to three separate objects, a LocalDateTime, a ZoneId and the resolved ZoneOffset. The offset and local date-time are used to define an instant when necessary. The zone ID is used to obtain the rules for how and when the offset changes. The offset cannot be freely set, as the zone controls which offsets are valid.

一个 ZonedDateTime 相当于持有三个独立对象的状态,一个 LocalDateTime,一个 ZoneId 和已解决的 ZoneOffset。必要时,偏移量和 local date-time 被用来定义一个瞬间。zone ID 被用来获取偏移量及何时变化的规则。偏移量不能自由设置,因为时区控制着哪些偏移量时有效的。

This class is immutable and thread-safe.

这个类是不可变的,并且是线程安全的。

withZoneSameLocal 和 withZoneSameInstant 的使用与区别

withZoneSameLocal 简介

先看 withZoneSameLocal 方法的注释:

Returns a copy of this date-time with a different time-zone, retaining the local date-time if possible.

This method changes the time-zone and retains the local date-time. The local date-time is only changed if it is invalid for the new zone, determined using the same approach as ofLocal(LocalDateTime, ZoneId, ZoneOffset).

To change the zone and adjust the local date-time, use withZoneSameInstant(ZoneId).

This instance is immutable and unaffected by this method call.

@param zone – the time-zone to change to, not null

@return a ZonedDateTime based on this date-time with the requested zone, not null

返回一个具有不同时区的 date-time 的副本,如果可能的话,保留 local date-time。

这个方法改变了时区并保留了 local date-time。在新的时区无效时,local date-time 才会被改变,与使用 ofLocal(LocalDateTime, ZoneId, ZoneOffset) 方法相同。

要改变区域并调整 local date-time,请使用 withZoneSameInstant(ZoneId)。

被调用实例是不可变的,不受此方法调用的影响。

形参:zone - 要改变的时区,不为 null。

返回值:a ZonedDateTime - 基于该 date-time 的请求时区,不为 null。

简单来说就是修改时区但是保持 local date-time 不变:

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
System.out.println(zonedDateTime.withZoneSameLocal(ZoneId.of("Europe/Moscow")));

// 输出结果为
2022-08-08T18:45:22.711+08:00[Asia/Shanghai]
2022-08-08T18:45:22.711+03:00[Europe/Moscow]

withZoneSameInstant 简介

再看 withZoneSameInstant 方法注释:

Returns a copy of this date-time with a different time-zone, retaining the instant.

This method changes the time-zone and retains the instant. This normally results in a change to the local date-time.

This method is based on retaining the same instant, thus gaps and overlaps in the local time-line have no effect on the result.

To change the offset while keeping the local time, use withZoneSameLocal(ZoneId).

@param zone – the time-zone to change to, not null

@return a ZonedDateTime based on this date-time with the requested zone, not null

@throws DateTimeException – if the result exceeds the supported date range

返回一个具有不同时区的 date-time 的副本,保留 instant。

这个方法改变了时区并保留了 instant。这通常会导致 local date-time 的改变。

这个方法是基于保留相同的 instant,因此本地时间线的间歇和重叠对结果没有影响。

要保持 local date-time 的同时改变偏移量,请使用 withZoneSameLocal(ZoneId)。

形参zone - 要改变的时区,不为 null。

返回值:a ZonedDateTime - 基于该 date-time 的请求时区,不为 null。

抛出:DateTimeException – 如果结果超出了支持的日期范围。

简单来说就是修改时区但是保持 instant 不变。因为时区变了,偏移量肯定变了,所以 local date-time 也会改变以保持 instant 不变。

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
System.out.println(zonedDateTime.withZoneSameInstant(ZoneId.of("Europe/Moscow")));

// 输出结果为
2022-08-09T20:06:35.753+08:00[Asia/Shanghai]
2022-08-09T15:06:35.753+03:00[Europe/Moscow]

……

疑问

我了解的并不全面,或者是因为英语能力有限,原本要和上下文关联理解的地方没翻译好,导致我有以下疑问。如果你知道,欢迎联系我!

  • 文中 “or the previous offset is invalid”、“The local date-time is only changed if it is invalid for the new zone” 这两段话的无效偏移量、时区具体指的是什么?

参考

  • 时区信息数据库 - 维基百科,自由的百科全书
  • List of tz database time zones - Wikipedia
  • 夏令时 - 维基百科,自由的百科全书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/620741.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

攻防世界-web-supersqli

1. 题目描述: 2. 思路分析 这里尝试按照基本思路进行验证,先确定注入点,然后通过union查询依次确认数据库名,表名,字段名,最终获取到我们想要的字段信息。 这里只有一个输入框,所以注入点肯定…

【犀牛书】JavaScript 类型、值、变量章节读书笔记

本文为对《JavaScript权威指南》第三章:类型、值、变量精读的读书笔记,对重点进行了记录以及在一些地方添加了自己的理解。 JavaScript类型可以分为两类:原始类型和对象类型。Javascript的原始类型包括数值、文本字符串(也称字符串…

驱动操作控制LED灯

控制LED灯: 驱动如何操作寄存器 rgb_led灯的寄存器是物理地址,在linux内核启动之后, 在使用地址的时候,操作的全是虚拟地址。需要将物理地址 转化为虚拟地址。在驱动代码中操作的虚拟地址就相当于 操作实际的物理地址。 物理地址&…

2023年5月榜单丨飞瓜数据B站UP主排行榜(哔哩哔哩)发布!

飞瓜轻数发布2023年5月飞瓜数据UP主排行榜(B站平台),通过充电数、涨粉数、成长指数三个维度来体现UP主账号成长的情况,为用户提供B站号综合价值的数据参考,根据UP主成长情况用户能够快速找到运营能力强的B站UP主。 飞…

Git—版本管理工具

作用:分布式版本控制 一句话:在开发的过程中用于管理对文件、目录或工程等内容的修改历史,方便查看历史记录,备份以便恢复以前的版本的软件工程技术 官网下载安装:https://git-scm.com/ 命令大全:https://g…

OceanBase 4.1 全面测评及部署流程,看这篇就够了【建议收藏】

背景 测试 OceanBase 对比 MySQL,TiDB 的性能表现,数据存储压缩,探索多点内部项目一个数据库场景落地 Oceanbase(MySQL->OceanBase)。 单机测试 准备 OBD 方式部署单机 文件准备 wget https://obbusiness-pri…

Bilinear CNN:细粒度图像分类网络,对Bilinear CNN中矩阵外积的解释。

文章目录 一、Bilinear CNN 的网络结构二、矩阵外积(outer product)2.1 外积的计算方式2.2 外积的作用 三、PyTorch 网络代码实现 细粒度图像分类(fine-grained image recognition)的目的是区分类别的子类,如判别一只狗…

【web自动化测试】Web网页测试针对性的流程解析

前言 测试行业现在70%是以手工测试为主,那么只有20%是自动化测试,剩下的10%是性能测试。 有人可能会说,我现在做手工,我为什么要学自动化呢?我去学性能更好性能的人更少? 其实,性能的要求比自动…

蓝桥杯2022年第十三届决赛真题-齿轮

题目描述 这天,小明在组装齿轮。 他一共有 n 个齿轮,第 i 个齿轮的半径为 ri,他需要把这 n 个齿轮按一定顺序从左到右组装起来,这样最左边的齿轮转起来之后,可以传递到最右边的齿轮,并且这些齿轮能够起到提…

小程序容器与PWA是一回事吗?

PWA代表“渐进式网络应用”(Progressive Web Application)。它是一种结合了网页和移动应用程序功能的技术概念。PWA旨在提供类似于原生应用程序的用户体验,包括离线访问、推送通知、后台同步等功能,同时又具有网页的优势&#xff…

软件验收测试该怎么进行?权威的软件检测机构应该具备哪些资质?

软件测试是软件开发周期中非常重要的一个环节。软件测试的目的是发现软件在不同环境下的各种问题,保证软件在发布前能够达到用户的要求。软件验收测试是软件测试的最后一个环节,该环节主要验证软件是否满足用户需求。那么对于软件验收测试,该…

分布式事务二 Seata使用及其原理剖析

一 Seata 是什么 Seata 介绍 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本…

【Spring源码】Spring源码导入Idea

1.基础环境准备 相关软件、依赖的版本号 Spring源码版本 5.3.x软件 ideaIU-2021.1.2.exeGradle gradle-7.2-bin.zip https://services.gradle.org/distributions/gradle-7.2-bin.zip - 网上说要单独下载gradle并配置环境变量,亲测当前5.3.X版本通过gradlew的方式进…

虚函数详解及应用场景

目录 概述1. 虚函数概述2. 虚函数的声明与重写3. 析构函数与虚函数的关系4. 虚函数的应用场景4.1. 多态性4.2. 接口定义与实现分离4.3. 运行时类型识别4.4. 多级继承与虚函数覆盖 结论 概述 虚函数是C中一种实现多态性的重要机制,它允许在基类中声明一个函数为虚函…

PDCCH monitoring capability

欢迎关注同名微信公众号“modem协议笔记”。 前段时间看search space set group (SSSG) switching相关内容时,注意到R17和R16的描述由于PDCCH monitoring capability的变化,内容有些不一样。于是就顺带看了下R16 R17PDCCH monitoring capability的内容。…

Domino 14.0早期测试版本

大家好,才是真的好。 本篇是超级图片篇,图片多,内容丰富,流量党请勿手残。 前天我们说到Engageug2023正在如火如荼进行,主题是“The Future is Now”。 因为时差的关系,实际上在写这篇公众号时&#xff…

设计模式(七):结构型之适配器模式

设计模式系列文章 设计模式(一):创建型之单例模式 设计模式(二、三):创建型之工厂方法和抽象工厂模式 设计模式(四):创建型之原型模式 设计模式(五):创建型之建造者模式 设计模式(六):结构型之代理模式 设计模式…

Java --- springboot3之web内容协商原理

一、内容协商原理 HttpMessageConverter 定制 HttpMessageConverter 来实现多端内容协商 编写WebMvcConfigurer提供的configureMessageConverters底层,修改底层的MessageConverter ResponseBody由HttpMessageConverter处理 标注了ResponseBody的返回值 将会由支持它…

蹭个高考热度,中国人民大学与加拿大女王大学金融硕士项目给你更多的选择

今日各大平台热搜都被“高考”霸屏,朋友圈里到处都是高考的祝福。期待莘莘学子都将交上满意的答卷,考出理想的未来。针对职场上的我们而言高考已是过去时,但知识的力量却是无穷的,在职的我们依然可以向上生长,中国人民…

FreeRTOS_任务相关API函数

目录 1. 任务创建和删除 API 函数 1.1 函数 xTaskCreate() 1.2 函数 xTaskCreateStatic() 1.3 函数 xTaskCreateRestricted() 1.4 函数 vTaskDelete() 2. 任务创建和删除实验(动态方法) 2.1 实验程序与分析 3. 任务创建和删除实验(静…