您的结论是正确的:没有可靠的方法可以从offset-from-UTC识别时区。
对于您的偏移量示例,我在当前列表-07:00
中计算了大约三打可能的时区,包括:、、和。America/Boise
America/Chihuahua
America/Edmonton
时区实际上是偏移量的集合,记录了随着时间的推移所做的更改,该偏移量在该区域使用了一定的时间段,然后在另一个特定的时间段内发生了变化。
例如,America/Los_Angeles
每年的部分时间有一个偏移量,-08:00
而一年的另一部分有-07:00
. 因此,该时区每年累积至少两次偏移的历史记录。相比之下,使用时区的相邻区域America/Phoenix
并没有-07:00
累积其偏移量的变化,几十年来一直保持相同的偏移量。
所以我们在偏移量和时区之间存在多对多的关系。偏移量可能出现在一个或多个时区。并且每个时区可以有一个或多个偏移量(已经改变了历史)。
包括时区名称
这就是为什么 java.time 类的设计者ZonedDateTime
冒昧地让其toString
方法扩展标准ISO 8601格式,仅使用偏移量,并将时区名称附加在方括号中。
例如,2007-12-03T10:15:30+01:00
该类生成的不是简单地生成标准格式:,而是附加2007-12-03T10:15:30+01:00[Europe/Paris]
了区域Europe/Paris的名称。
ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
.toString()
2007-12-03T10:15:30+01:00[欧洲/巴黎]
我希望这种附加时区名称的做法能够流行起来。缺少时区名称是标准委员会的一个令人惊讶的遗漏,否则这些标准委员会在设计 ISO 8601 方面做得非常出色。
您可以使用业务场景上下文中的线索来猜测时区。但我不建议这样做。猜测是有风险的,特别是因为世界各地的政治家都喜欢频繁地重新定义时区。
世界标准时间
存储、序列化和交换日期时间值的最佳实践通常是调整为UTC。假设日期时间库的tzdata是最新的,调整为 UTC 可提供始终正确且明确的可靠值。
例如,在 Java 中,这意味着使用或提取Instant
对象。该类表示UTCInstant
时间线上的时刻,分辨率为纳秒(最多九 (9) 位小数)。
Instant instant = Instant.now();
……或者……</p>
ZonedDateTime zdt = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
Instant instant = zdt.toInstant();
表示此类值的标准 ISO 8601 格式字符串使用 aZ
作为 UTC 的缩写Zulu
,表示 UTC。
2007-12-03T09:15:30Z
OffsetDateTime
如果给定一个表示只有偏移量的日期时间的字符串,请将其解析为OffsetDateTime
对象。
OffsetDateTime odt = OffsetDateTime.parse( "2007-12-03T10:15:30+01:00" );
odt.toString(): 2007-12-03T10:15:30+01:00
从那里您可以提取一个 UTC 值,一个Instant
.
Instant instant = odt.toInstant();
即时.toString(): 2007-12-03T09:15:30Z
或者您可以调整到所需的时区以获得与对象相同的时刻ZonedDateTime
。
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
zdt.toString(): 2007-12-03T14:45:30+05:30[亚洲/加尔各答]
术语:“本地”</h1>
我建议您在提及调整为区域特定挂钟时间的日期时间时避免使用“本地”一词。java.time 类和其他上下文中的“本地”一词表示任何地方,而不是特定的地方。本地日期时间不是时间线上的特定时刻,只是关于一系列可能时刻的粗略概念。
例如,今年圣诞节开始的当地日期时间是2017-12-25T00:00:00
,但奥克兰的午夜时刻比加尔各答早得多,在巴黎还要晚几个小时,而在蒙特利尔则更晚几个小时。
我建议您改用这些术语zoned
,或者wall-clock time
当您指的是通过特定时区的镜头看到的特定时刻时。
提示:偏移文字
-7
这个问题在提到偏移量时碰巧使用了这些字母。我总是建议:
- 根据 ISO 8601 的要求,使用带有填充零的两位数
- 正如某些库和格式所期望的那样,同时使用小时和分钟。
所以使用-07:00
而不是-7
.