使用和不使用 TIMEZONE 存储 DATETIME

Storing DATETIME with and without TIMEZONE

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

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

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

如果值为:

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

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

  • TIMESTAMP(在某些数据库中也更清楚地称为 TIMESTAMP WITHOUT TIME ZONE
  • TIMESTAMP WITH TIME ZONE

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

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

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

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

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

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

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

不幸的是,这里有一个皱纹。通常,工具和中间件会注入一个默认时区,将检索到的 UTC 时刻调整到某个时区。虽然本意是好的,但这个反特征造成了价值存储在那个时区的错觉。但是实际存储在 UTC 中的值,至少对于 Postgres 这样的数据库是这样。

你问过:

2021-12-02 14:45:00 Wouldn't that value be inserted as 2021-12-02 14:45:00 UTC in both data types?

没有

  • 在数据类型类似于 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 … Or, would the 2:45PM be stored as "2:45 PM UTC" in the DATETIME type but would be stored as (if using EST) 2:45 PM EST --> 6:45 PM UTC in the TIMESTAMP type?

“可能是”,第一个条款。但是根本没有 EST 涉及。日期按原样存储,2021-12-02,以及时间按原样存储,14:45:00。 EST 部分被忽略并丢弃。 (但在您的特定工具中进行实验以验证此行为。)

第二个子句是“也许”。如上文最后一项所述,TIMESTAMP WITH TIME ZONE 的行为可能会有所不同。阅读文档,并进行实验。

你说:

though most databases store this the same

不,不正确。那将是一个非常的大“不”。

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

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

你说:

I guess I'm not following why the timezone-aware and no-timezone need to be stored as two different types if all date/times get stored as UTC anyways.

您错误地认为“无时区”类型存储在 UTC 中。它没有。

这就是“无时区”的意思:不考虑偏移量或时区,不考虑任何偏移量或时区,不对任何偏移量或时区进行调整,没有偏移量或时区的概念。 TIMESTAMP WITHOUT TIME ZONE 类型简单地表示字面上的日期、时间,仅此而已。超出此范围的任何事情要么是 (a) 您的想象,要么是 (b) 受到您的 middleware/tooling/drivers.

的干扰