时区仅仅是一个偏移量还是“更多的信息”?

3
我居住的国家每年会两次更改时间。也就是说,一年中有一个时期,与协调世界时(UTC)的偏差为-3小时(-180分钟),而另一个时期则偏差为-4小时(-240分钟)。
图示如下:
       |------- (offset = -3) -------|------- (offset is -4) -------|
start of year                      mid                            end of year

我的问题是:
“时区”只是表示偏移量的数字吗?也就是说,我的国家有两个时区吗?还是时区包括这些信息?

这很重要,因为我在数据库中保存每个日期的UTC时区(偏移量= 0)。

相反,我应该使用本地时区保存日期并保存它们的偏移量(在保存时)吗?

以下是我通过使用UTC时区保存日期所看到的问题的示例:
假设我有一个系统,人们可以发送消息。
我想要拥有一个统计部分,其中我绘制“按小时发送的消息数”(即:“正常日中按小时发送的消息数”)

假设整个数据库中只有两条消息:

  1. 消息1,在3月1日UTC时间下午5点发送(当地时间下午2点)
  2. 消息2,在8月1日UTC时间下午5点发送(当地时间下午1点)

那么,如果我在8月2日创建图表,并将这些UTC日期转换为本地日期,则会给我提供“有2条消息在下午1点发送”的错误信息!


偏移量很方便,但无法捕捉政治现实。例如,我在萨斯喀彻温省,该省属于中央标准时间(CST),但一直保持UTC-6不变(我们不遵循夏令时)。 - Marc B
将所有内容存储为UTC,并将其转换为特定于当地语言环境的形式,以供人类阅读。 - msw
另一种思考方式是,在夏令时期间,时钟会出现错误。你的例子涉及语义问题,没有正确答案,只有你认为对用户有意义的答案。 - msw
3个回答

5

来自标签维基在StackOverflow这里

时区!=偏移量

时区不能仅由与UTC的偏移表示。许多时区由于“夏令时”或“夏季时间”规则而具有多个偏移量。偏移更改的日期也是时区规则的一部分,历史偏移更改也是如此。许多软件程序、库和Web服务忽略了这个重要细节,并错误地称标准或当前偏移为“区域”。这可能会导致混淆和数据误用。请尽可能使用正确的术语。

有两个常用的数据库,Microsoft Windows时区数据库和IANA/Olson时区数据库。有关详细信息,请参见维基

您的具体问题:

"时区"只是代表偏移量的数字吗?也就是说,我的国家有两个时区吗?还是时区包含了这些信息?

您只有一个"时区"。它包含两个"偏移量"。

相反,我应该使用本地时区保存日期并在保存时保存它们的偏移量吗?

如果您记录事件发生或将要发生的精确时间点,则应将该特定时间的偏移量与其一起存储。在.NetSQL Server中,这是使用DateTimeOffset表示的。其他平台上也有类似的数据类型。它仅包含偏移信息 - 不包含偏移来源的时区。通常,它以ISO8601格式序列化,例如:

2013-05-09T13:29:00-04:00

如果您需要编辑该时间,则不能仅存储偏移量。在系统中的某个地方,您还需要具有时区标识符。否则,在进行编辑后,您无法确定新偏移量应该是多少。如果您希望,可以将此与值本身一起存储。一些平台专门为此目的提供了对象,例如NodaTime中的ZonedDateTime。示例:
2013-05-09T13:29:00-04:00  America/New_York

即使存储了时区ID,仍需要记录偏移量。这是为了解决从夏令时偏移到标准偏移的“回退”转换中的歧义。
或者,您可以使用UTC时间与时区名称一起存储时间。
2013-05-09T17:29:00Z  America/New_York

这种方法同样可行,但您需要在向任何人显示值之前应用时区。 OraclePostgreSQL 中的 TIMESTAMP WITH TIME ZONE 就是这样工作的。
您可以在this post中阅读更多相关内容,虽然它是针对 .Net 的,但这个想法也适用于其他平台。您提供的示例问题是我所说的“维护观察者的视角”问题,在同一篇文章中讨论了这个问题。

一个很好的回答,但有一个可能会引起困惑的地方:TIMESTAMP WITH TIME ZONE 不会存储传入数据的时区。传入的时区或偏移量用于调整到 UTC,然后被丢弃。该数据类型的名称是一个误称。可以将其视为“带有对时区的尊重的时间戳”。相反的类型 TIMESTAMP WITHOUT TIME ZONE 忽略任何给定的时区或偏移量。你的示例文本可能会让人误以为数据库正在存储“America/New_York”,但实际上并不是这样。也许应该编辑一下回答以澄清这一点。 - Basil Bourque
@BasilBourque - 如果我没记错的话,这是一个因数据库而异的实现细节。如果我说错了,请纠正我,但我相信Postgres会调整为UTC,而Oracle则将值存储为呈现的形式。 - Matt Johnson-Pint

2
这是什么意思:我的国家有两个时区?还是时区包括了这些信息?
“时区”一般包括这些信息。例如,在Java中,“TimeZone表示时区偏移量,并且可以计算夏令时”(link),在类Unix系统中,tz数据库包含了夏令时的信息。
不过,对于单个时间戳,通常只给出UTC偏移量而不是完整的时区标识符。
另外,你应该查阅你的数据库文档,或者至少说明你正在使用的数据库以及访问它的工具(例如,驱动程序、编程语言等)。

1
这是一个描述时区的非常流行的格式(虽然不是Windows使用的格式)示例
你可以看到它不仅仅是一个简单的偏移量,更多地涉及到偏移量和规则集合(随时间变化而变化),以确定何时使用哪个偏移量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接