存储带或不带 TIMEZONE 的 DATETIME

Dav*_*542 3 sql database timezone datetime types

数据库通常将不带时区的日期时间作为单独的类型存储为带时区的日期时间。作为示例,我将使用 BigQuery(尽管大多数数据库都以相同的方式存储它):

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

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

  • 2021-12-02 14:45:00

该值不会像两种数据类型一样插入吗2021-12-02 14:45:00 UTC?或者,下午 2:45 是否会在 DATETIME 类型中存储为“2:45 PM UTC”,但在 TIMESTAMP 类型中会存储为(如果使用 EST)2:45 PM EST --> 6:45 PM UTC?

如果值为:

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

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

Bas*_*que 6

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

\n
    \n
  • TIMESTAMP(在 Postgres 等一些数据库中也更清楚地知道为TIMESTAMP WITHOUT TIME ZONE
  • \n
  • TIMESTAMP WITH TIME ZONE
  • \n
\n

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

\n

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

\n

不幸的是,SQL 规范很少提及各种日期时间类型和行为。因此,各种数据库产品对这些类型的支持及其对行为的解释差异很大。

\n

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

\n

在某些数据库(例如 Postgres)中,提交到包含区域或偏移量指示符的第二类型列 ( TIMESTAMP WITH TIME ZONE) 的值在写入数据库之前将其日期和时间调整为 UTC。在此类数据库中,此类型始终采用 UTC 格式,即表示偏移量为零的时刻。

\n

什么是偏移量?+仅比 UTC 早 ( ) 或晚 UTC ( )几个小时-分钟-秒-。相比之下,时区的意义要大得多。时区有一个Continent/Region格式名称,包含特定地区的人民所使用的偏移量的过去、现在和未来的变化,由他们的政治家决定。

\n

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

\n

不幸的是,这里有一个问题。工具和中间件通常会注入默认时区,将检索到的 UTC 时刻调整到某个时区。虽然本意是好的,但这种反功能会造成一种错觉,即该值是在该时区存储的。但这些值实际上存储在 UTC 中,至少对于 Postgres 等数据库来说是这样。

\n

你问:

\n
\n

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

\n
\n

不。

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

你问:

\n
\n

2021-12-02 14:45:00 \xe2\x80\xa6 或者,下午 2:45 是否会在 DATETIME 类型中存储为“2:45 PM UTC”,但会存储为(如果使用 EST)2:45 PM EST --> 6:45 PM UTC(时间戳类型)?

\n
\n

\xe2\x80\x9d 对于第一个子句,可能是\xe2\x80\x9d。但EST根本没有参与。日期按原样存储,即 2021 年 12 月 2 日,以及时间按原样存储,即 14:45:00。这EST部分被忽略并丢弃。(但是请在您的特定工具中进行实验以验证此行为。)

\n

第二个子句为 \xe2\x80\x9cmaybe\xe2\x80\x9d 。正如上面最后一个项目符号中所讨论的, 的行为TIMESTAMP WITH TIME ZONE可能会有所不同。阅读文档并进行实验。

\n

你说:

\n
\n

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

\n
\n

不,不正确。那将是一个非常大的\xe2\x80\x9cNo\xe2\x80\x9d。

\n

数据库在对日期时间功能的支持、日期时间类型的种类、类型的名称、类型的技术细节以及数据库服务器、中间件、驱动程序和工具的行为方面存在很大差异。

\n

一些较旧的数据库系统的旧数据类型已被新类型取代,但仍然受支持,这使情况进一步复杂化。

\n

你说:

\n
\n

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

\n
\n

您错误地假设 \xe2\x80\x9cno-timezone\xe2\x80\x9d 类型以 UTC 存储。它不是。

\n

这就是 \xe2\x80\x9cno-timezone\xe2\x80\x9d 的含义:不考虑偏移量或区域,不考虑任何偏移量或区域,不调整任何偏移量或区域,并且没有偏移量或区域的概念区。从字面上看,类型TIMESTAMP WITHOUT TIME ZONE简单地意味着日期、一天中的时间,仅此而已。除此之外的任何东西要么是(a)你的想象的虚构,要么(b)你的中间件/工具/驱动程序的干扰。

\n