"UTC不是一个时区"这种说法实际上并不准确。
UTC是一个标准,而非时区(正如您已经链接的那样)。
时区对应于世界上的某个地区,并具有许多关于该地区的规则:
- 在夏令时和非夏令时中UTC偏移量(与UTC的差异)是多少
- 夏令时何时开始和结束
- 该地区在其历史上所有偏移和夏令时的更改
例如:1985年,巴西阿克里州的标准偏移量为
UTC-05:00
(夏令时为
UTC-04:00
),然后在1988年没有夏令时的情况下为
UTC-05:00
,然后在2008年标准偏移量改为
UTC-04:00
(无夏令时),自2013年以来它又回到了
UTC-05:00
,没有夏令时。
虽然时区跟踪所有这些变化,但UTC没有这样的规则。您可以以许多不同的方式考虑UTC:
- 一个“基本”日期/时间,每个人都相对于此进行 - 与UTC的差异称为“偏移量”。今天,圣保罗在
UTC-03:00
(偏移量为
减去3小时,或比UTC晚3小时),而东京在
UTC+09:00
(偏移量为
加9小时,或比UTC早9小时)。
- 一个“特殊”的时区,从不变化。它始终处于相同的偏移量(零),永远不会更改,也不会有夏令时转换。
由于“UTC的偏移量”(不确定这个术语在技术上是否准确)始终为零,通常将其写为 UTC + 00:00
或 Z
。
UTC和时区的另一个区别是,时区由政府和法律定义,并且可以随时/任何地方更改。如上所述,阿克里所有的更改都是由政治家们出于当时的某些原因而定义的。(因此,即使今天某个地区在其时区中遵循UTC,也无法保证将来它会保持不变,这就是为什么即使这些地区看起来多余,它们也拥有自己的时区)。
但是,无论政治家们更改他们地区的偏移多少次,它们必须相对于UTC(当然,直到出现新标准)。
现在,当你看到像
TimeZone.getTimeZone("UTC")
这样的实现时,你可以用两种不同的方式来思考它:
对我来说,这是两者的混合(五五开)。
新的java.time API将概念分为两个类:ZoneRegion
和ZoneOffset
(实际上两者都是ZoneId
的子类,但是ZoneRegion
不是公共的,因此我们实际上使用ZoneId
和ZoneOffset
):
- 如果你使用带有IANA时区名称的
ZoneId
(始终以大陆/城市
格式,如America/Sao_Paulo
或Europe/Berlin
),它将创建一个ZoneRegion
对象——一个“真正”的时区,包含其历史上的所有DST规则和偏移量。因此,在这个ZoneId
中使用不同的日期,可以有不同的偏移量。
- 如果你使用
ZoneOffset
(带有Z
、UTC
、+03:00
等),它只会返回一个表示偏移量的对象:与UTC的差异,但没有任何DST规则。无论你使用这个对象的日期是什么,它与UTC的差异始终相同。
因此,
ZoneId
(实际上是
ZoneRegion
)与某个区域(在某个
时区中)的偏移随时间变化(由于DST规则、政治家改变事物等原因)保持一致。而
ZoneOffset
表示与UTC的
差异的概念,它没有DST规则且永远不会更改。
还有一个特殊的常量ZoneOffset.UTC
,它表示与UTC的零差异(即UTC本身)。请注意,新API采用了不同的方法:它并没有说所有东西都是时区,而UTC是一种特殊类型,而是说UTC是一个ZoneOffset
,其偏移量为零。
您仍然可以认为这是一种"错误"的设计决策或使事情变得更简单的简化(或两者混合)。在我看来,与旧的java.util.TimeZone
相比,这个决定是一个巨大的改进,因为它清楚地表明UTC不是一个时区(在它没有DST规则且永远不会更改的意义上),它只是与UTC标准的零差异(一种非常技术性的说法就是"它是UTC")。
同时,它也将时区和偏移量的概念分开(虽然它们非常相关)。我认为将UTC定义为特殊偏移量是一种“实现细节”。创建另一个类来处理UTC将是冗余且令人困惑的,将其保留为
ZoneOffset
是一个很好的决定,简化了事情并没有混乱API(对我而言,是一个公平的权衡)。
我相信许多其他系统采取类似的方法(这解释了为什么Windows在时区列表中有UTC)。
ZoneOffset
声明为ZoneId
的子类来“欺骗”,因此它声称偏移量也是一种时区。请注意,本翻译尽可能保留原文意思,同时使语言更加通俗易懂。 - Ole V.V.SimpleDateFormat
是一种可怕的日期时间类之一,早在现代 java.time 类出现多年前就被取代了。这些遗留类是由那些不理解日期时间处理复杂性和微妙之处的人构建的。时区和UTC偏移量之间的区别是遗留类设计者不理解的重要点之一。不要从遗留类中学习任何课程;只需忽略它们并转向 java.time,就像 Sun、Oracle 和 JCP 社区一样。 - Basil BourqueZoneId.of("UTC")
返回一个有效的ZoneId
对象。 - yaskovdevZoneId
的子类ZoneOffset
声明了一个常量ZoneOffset.UTC
。该常量仅是一个偏移量,其值为零小时、零分钟和零秒钟。可能让您感到困惑的是,“UTC”一词经常用作该短语“一个偏移量,其值为零小时、零分钟和零秒”的缩写。这个词“UTC”有两个含义:(a) 缩写短语,(b) 一个正式定义的时间系统。 - Basil Bourque