关于utc:时区只是一个偏移号码还是“更多信息”?

Is timezone just an offset number or “more information”?

我住在一个一年两次改变时间的国家。也就是说,在一年中有一段时间与UTC的时差为-3小时(-180分钟),而其他时间段的时差为-4小时(-240分钟)。

Grafically:

1
2
       |------- (offset = -3) -------|------- (offset is -4) -------|
start of year                      mid                            end of year

我的问题是:"时区"只是表示偏移量的数字?那就是:我的国家有两个时区?或者时区包含这些信息?

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

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

以下是我通过保存时区为UTC的日期看到的一个问题的示例:假设我有一个人们发送信息的系统。我想有一个统计部分,在这里我绘制"发送的消息v/s小时"(即:"常规日期中按小时发送的消息")。

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

  • 消息1,3月1日在UTC时间下午5点(当地时间下午2点)发送
  • 8月1日下午5点(当地时间下午1点)发送的消息2
  • 然后,如果我在8月2日创建绘图,将这些UTC日期转换为本地日期将给我提供:"下午1点发送的2条消息",这是不稳定的信息!


    在StackOverflow上的时区标记wiki中:

    TimeZone != Offset

    A time zone can not be represented solely by an offset from UTC. Many
    time zones have more than one offset due to"daylight savings time" or
    "summer time" rules. The dates that offsets change are also part of
    the rules for the time zone, as are any historical offset changes.
    Many software programs, libraries, and web services disregard this
    important detail, and erroneously call the standard or current offset
    the"zone". This can lead to confusion, and misuse of the data. Please
    use the correct terminology whenever possible.

    有两个常用的数据库:Microsoft Windows时区数据库和IANA/OLSON时区数据库。有关详细信息,请参阅wiki。

    您的具体问题:

    the"timezone" is just the number representing the offset? that is: my country has two timezones? or the timezone includes this information?

    你有一个"时区"。它包括两个"补偿"。

    Should I, instead, be saving the dates with local timezone and saving their offset (at the moment of saving) too?

    如果您正在记录事件发生或将发生的精确时刻,那么您应该用它存储特定时间的偏移量。在.NET和SQL Server中,这是使用DateTimeOffset表示的。其他平台中也有类似的数据类型。它只包含偏移信息,而不包含偏移源所在的时区。通常,它以ISO8601格式序列化,例如:

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

    如果您可能需要编辑该时间,那么就不能只存储偏移量。在您的系统中的某个地方,您还需要有时区标识符。否则,您将无法确定在进行编辑后新偏移应该是什么。如果您愿意,您可以将其与值本身存储在一起。有些平台有这样的对象——比如nodatime中的ZonedDateTime。例子:

    1
    2013-05-09T13:29:00-04:00  America/New_York

    即使在存储区域ID时,仍然需要记录偏移量。这是为了解决从日光偏移到标准偏移的"后退"转换过程中的模糊性。

    或者,您可以使用时区名称将时间存储在UTC中:

    1
    2013-05-09T17:29:00Z  America/New_York

    这也可以,但是在向任何人显示值之前,您必须应用时区。Oracle和PostgreSQL中的TIMESTAMP WITH TIME ZONE就是这样工作的。

    您可以在本文中阅读更多关于这一点的内容,同时关注.NET——这个想法也适用于其他平台。您给出的示例问题是我所说的"维护观察者的视角"——这将在同一篇文章中讨论。


    that is: my country has two timezones? or the timezone includes this information?

    术语"时区"通常包括这些信息。例如,在Java中,"EDCOX1×0"表示时区偏移,并且还计算出"夏令时"(link),并且在类似UNIX的系统上,EDCOX1×1数据库包含DST信息。

    但是,对于单个时间戳,我认为只给出一个UTC偏移量比完整的时区标识符更常见。

    […] in my database.

    当然,您应该查阅数据库的文档,或者至少指出您正在使用的数据库,以及访问它所使用的工具(例如,什么驱动程序、什么语言)。


    下面是一个描述时区的非常流行的格式的例子(尽管不是Windows使用的格式)。

    你可以看到它不仅仅是一个简单的偏移。更多的是沿着偏移线和规则集(随时间变化)来确定何时使用哪个偏移。