提问人:M. A. Tanaka 提问时间:11/4/2023 最后编辑:user85421M. A. Tanaka 更新时间:11/10/2023 访问量:110
UTC(ZoneId)和(ZoneOffSet)有什么区别
What is the difference between UTC (ZoneId) and (ZoneOffSet)
问:
出于好奇,有没有人知道 Java 中 UTC 作为 ZoneId 和 ZoneOffset 之间的区别。
我有点惊讶,在比较 zoneid 和 zoneoffset 的 utc 时,情况并非如此
我试图用 spock 编写这个测试,我唯一能找到的是区域不同。
有没有人建议何时使用哪一个?
从示例中不清楚,但我实际上使用了 spock/groovy,其中 == 对应于 java 中的 equals 方法,因此对此表示歉意
但是无论我是否编写 lhs.equals(rhs),它仍然会返回 false
LocalDateTime now = LocalDateTime.now() // 2023-11-03T19:42:41.772234517
ZonedDateTime lhs = now.atZone(ZoneOffset.UTC)
String lhsString = lhs.toString() // 2023-11-03T19:42:41.772234517Z
ZonedDateTime rhs = now.atZone(ZoneId.of('UTC'))
String rhsString = rhs.toString() // 2023-11-03T19:42:41.772234517Z[UTC]
Duration duration = Duration.between(lhs, rhs) // PT0S
boolean equal = lhs == rhs // this is false
答:
从 ZoneId 文档:
ZoneId 用于标识用于在 Instant 和 LocalDateTime 之间进行转换的规则。
世界不同地区有不同的时区偏移量。ZoneId 类中捕获了偏移量如何随地点和时间而变化的规则。
例如,巴黎在冬季比格林威治/UTC 早一小时,在夏季比格林威治早两小时。Paris 的 ZoneId 实例将引用两个 ZoneOffset 实例 - 一个用于冬季的 +01:00 实例,一个用于夏季的 +02:00 实例。
因此,如果该地区使用夏令时,则区别在于夏令时与冬令时(夏令时)。同一时区中可能有不同的州或国家,例如,墨西哥城和芝加哥位于同一区域偏移量 (GMT-5),但墨西哥在 2023 年春季停止在夏令时和冬令时之间切换,因此在夏季他们休息一个小时,在冬季他们会再次匹配。
因此,如果要显示或转换为本地时间,请始终使用 ZoneId,它考虑了位置(州)和当地夏令时规则。
评论
equals
"UTC".equals("Z")
false
在这种情况下,双等相等运算符将简单地比较对象的实例。
由于 lhs 和 rhs 被分配了不同的实例,因此这些值将返回 false。
通常,Object#equals 方法将返回内容是否相等。
boolean equal = lhs.equals(rhs)
如果没有,请实现您自己的比较方法。
评论
引用我自己的评论:
Z 只是 UTC 的军事等价物,那里的方法应该更精确一些。在 JDK 中进行调试时,最终归结为两个区域 ID 的比较,以及计算结果为 .JDK 本身在不同的上下文中使用两者,因此它也应该知道它们是等价的。
equals
"UTC".equals("Z")
false
话虽如此,您的解决方法是使用:ZoneId.normalized()
package de.scrum_master.stackoverflow.q77419050
import spock.lang.Specification
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.temporal.ChronoUnit
class TimeZoneTest extends Specification {
def test() {
given:
def now = LocalDateTime.now()
when:
def lhs = now.atZone(ZoneOffset.UTC.normalized())
def rhs = now.atZone(ZoneId.of('UTC').normalized())
def timeDifference = Duration.between(lhs, rhs).get(ChronoUnit.SECONDS)
then:
lhs == rhs
timeDifference == 0
}
}
在 Groovy Web 控制台中尝试一下,
更多细节可以在这个答案中找到。
评论
==
now.atZone(ZoneOffset.UTC) == now.atZone(ZoneOffset.UTC)
false
now.atZone(ZoneOffset.UTC).equals( now.atZone(ZoneOffset.UTC) )
true
ZonedDateTime
equals