存储带和不带TIMEZONE的DATETIME



数据库通常将不带时区的日期时间作为单独的类型存储为带时区的时间。举个例子,我将使用BigQuery(尽管大多数数据库都存储相同的查询):

  • DATETIME是一个不存储时区的日期/时间
  • TIMESTAMP是存储时区的日期/时间

我抽象地理解;12月2日下午2:45";在日本和在纽约是不同的时间,但我想知道,如果应用程序将所有日期存储在UTC中,为什么这很重要。例如,如果要插入的值为:

  • 2021-12-02 14:45:00

该值不是作为2021-12-02 14:45:00 UTC插入两种数据类型中吗?或者下午2:45PM是否存储为"0";UTC下午2:45";在DATETIME类型中,但是将被存储为(如果使用EST)美国东部时间下午2:45-->下午6:45 UTC在TIMESTAMP类型?

如果值是:

  • 2021-12-02 14:45:00 EST

该值是否也作为2021-12-02 18:45:00 UTC插入两种数据类型中,并以相同的方式存储?似乎只有"时区"在查询端,难道它不能充当游标变量或字段上的某种元数据(类似于NULL检查)吗?我想我不明白为什么如果所有日期/时间都存储为UTC,那么时区感知和无时区需要存储为两种不同的类型。

SQL标准为一天中的日期和时间定义了两种类型:

  • TIMESTAMP(在一些数据库中也更清楚地称为TIMESTAMP WITHOUT TIME ZONE,如Postgres)
  • TIMESTAMP WITH TIME ZONE

第一种类型是故意缺少时区或UTC偏移量的任何上下文。因此,明年1月23日中午,2022-01-23 12:00,意味着任何地方的中午。这意味着日本东京的中午,法国图卢兹的中午,以及美国俄亥俄州托莱多的中午。这些都是明显不同的时刻,相隔几个小时。因此,这种类型不能代表一个时刻,不是时间线上的特定点。

第二种类型确实代表一个时刻,是一个时间线上的特定点。当您想跟踪实际时刻时,例如当一行被写入数据库时,或者当货物到达仓库时,请使用此类型。

不幸的是,SQL规范对各种日期-时间类型和行为几乎没有说明。因此,各种数据库产品对这些类型的支持以及对行为的解释各不相同。

在一些数据库(如Postgres)中,提交到包含区域或偏移量指示符的第一类型列(TIMESTAMP WITHOUT TIME ZONE)的值将记录为已提交的日期和时间。未进行任何调整。任何区域或偏移输入都将被忽略并丢弃。

在一些数据库(如Postgres)中,提交给第二种类型(TIMESTAMP WITH TIME ZONE)的列(包含区域或偏移量指示符)的值在写入数据库之前,其日期和时间将调整为UTC。在这样的数据库中,此类型是始终使用UTC,也就是说,表示偏移量为零的时刻。

什么是偏移?仅领先UTC(+)或落后UTC(-)几个小时-分-秒。相比之下,时区要多得多。时区的名称采用Continent/Region格式,包含特定地区人民根据其政治家的决定使用的偏移量的过去、现在和未来的历史变化。

因此,Postgres等数据库中的TIMESTAMP WITH TIME ZONE类型用词不当。数据库中未存储时区信息。随日期和时间一起提交的任何时区或偏移信息都将用于调整为UTC。区域/偏移信息随后被丢弃。因此,如果记住最初提交的区域对您来说很重要,您需要将其存储在第二列中。关于用词不当,你可以把类型想象成TIMESTAMP WITH REGARD FOR SUBMITTED OFFSET OR TIME ZONE。但要明确的是,在Postgres这样的数据库中,你的时刻存储在UTC中,始终是UTC,并且检索为UTC,始终是UTC。

不幸的是,这里有一条皱纹。通常,工具和中间件会注入一个默认时区,将检索到的UTC时刻调整到某个时区。虽然初衷是好的,但这种反功能造成了一种错觉,即值是用那个时区存储的。但这些值实际上存储在UTC中,至少在Postgres这样的数据库中是这样。

你问:

2021-12-02 14:45:00该值不是在两种数据类型中都插入为2021-12-0 14:45:00 UTC吗?

否。

  • 在类似于TIMESTAMP WITHOUT TIME ZONE的数据类型的列中,该日期和时间将存储为已提交,即今年12月2日下午3点之前的一个季度
  • 在类似于TIMESTAMP WITH TIME ZONE的数据类型的列中,存储的值可能取决于特定数据库和特定中间件、工具和驱动程序的行为。该行为可能只是假设你指的是UTC中的2021-12-02 14:45:00,并将其存储起来。或者,行为可能会假设你指的是在特定时区看到的2021-12-02 14:45:00。在Postgres等数据库中,在最终存储之前,将应用对UTC的调整。您必须研究特定数据库、中间件、工具和驱动程序的文档,以发现软件中会出现哪些行为。一定要进行实验来验证你的理解

你问:

2021-12-02 14:45:00…或者,2:45PM会被存储为";UTC下午2:45";在DATETIME类型中,但是将被存储为(如果使用EST)美国东部时间下午2:45-->下午6:45 UTC在TIMESTAMP类型?

"可能是",用于第一个子句。但根本没有涉及EST。日期按原样存储,即2021-12-02,以及一天中的时间,即14:45:00。EST部分被忽略并丢弃。(但是在您的特定工具中进行实验来验证这种行为。)

第二条用"也许"。正如上面最后一个项目符号中所讨论的,TIMESTAMP WITH TIME ZONE的行为可能会有所不同。阅读文档,进行实验。

你说:

尽管大多数数据库都存储相同的

否,不正确。这将是一个非常的大"否"。

数据库对日期-时间特性的支持、日期-时间类型的种类、类型的名称、类型的技术细节以及数据库服务器、中间件、驱动程序和工具的行为各不相同。

一些较旧的数据库系统的遗留数据类型被较新的类型所取代,但仍然支持所有类型,这使情况更加复杂。

你说:

我想我不明白为什么如果所有日期/时间都存储为UTC,那么时区感知和无时区需要存储为两种不同的类型。

您错误地认为"无时区"类型存储在UTC中。事实并非如此。

这就是"无时区"的含义:不考虑偏移量或区域,不考虑任何偏移量或分区,不调整任何偏移量和分区,也不考虑偏移或分区的概念。TIMESTAMP WITHOUT TIME ZONE类型的字面意思就是日期、一天中的某个时间,仅此而已。任何超过这一点的东西要么是(a)你想象的虚构,要么是(b)中间件/工具/驱动程序的干扰。