On this page
Overview
以下概述描述了与 SQL 标准和所选数据库供应商相比所需的时间戳记语义:
TIMESTAMP 和 TIMESTAMP 没有时区
TIMESTAMP 和 TIMESTAMP WITH TIME ZONE 类型的行为应类似于 Java 的LocalDateTime类,即每个值都是对 calendar 和挂在墙上的时钟可见的记录,例如“ 1969-07-20 16: 17:39”。可以将其分解为年,月,日,小时,分钟和秒字段,但是由于没有可用的时区信息,因此它不对应于任何特定的时间点。
此行为与 SQL 标准(2003 年及更高版本)一致。
时间戳与当地时区
TIMESTAMP WITH LOCAL TIME ZONE 类型的行为应类似于 Java 的Instant类,即,每个值标识单个 Moment,但不包含任何明确的时区信息。为了实现这种语义,时间戳 Literals 的处理涉及从会话本地时区到 sched 义的时区(通常但不一定是 UTC)的隐式规范化,而显示存储的时间戳涉及从 sched 义的时区到会话的隐式转换。 -本地的。尽管上面明确提到了 sched 义的时区(通常是 UTC),但它不是各个值的一部分,而是整个类型的定义。这样,必须将存储的每个值标准化到该 sched 义的时区,因此会丢失其原始时区信息。
例如,如果墙上的 calendar 和时钟根据美国东部夏令时间显示 1969-07-20 16:17:39,则必须将其存储为“ 1969-07-20 20:17:39”,因为该 UTC 时间对应于同一 Moment。当回读该值时,我们不再知道它源自 EDT 时间,我们只能在某个固定的时区(本地或 UTC 或由用户指定)中显示它。
此行为与某些主要的 DB 引擎一致,这是我们能做的最好的事情,因为 SQL 标准没有定义具有此行为的类型。
时区时间戳
TIMESTAMP WITH TIME ZONE 类型的行为应类似于 Java 的OffsetDateTime类,即每个单独的值也应包含时区偏移量。此定义导致产生时间戳,这些时间戳不仅可以明确标识特定的 Moment,而且还可以检索原始时区偏移量。
如果我们使用此语义存储与上述相同的时间戳,则可以重建原始时间戳 Literals,其中包括一些时区信息,例如“ 1969-07-20 16:17:39(UTC -04:00)”。 (通常仍将主要字段存储为标准化的 UTC,以使时间戳比较更加有效,但这是实现的详细信息,并且不会影响类型的行为.)
此行为与 SQL 标准(2003 年及更高版本)一致。
Comparison
让我们总结一下上述不同语义如何应用于插入到 SQL 表中的值的示例。
如果将时间戳 Literals'1969-07-20 16:17:39'插入华盛顿特区然后从巴黎查询,则可能会根据时间戳语义以以下方式显示:
SQL type | Semantics | Result | Explanation |
TIMESTAMP [WITHOUT TIME ZONE] | LocalDateTime | 1969-07-20 16:17:39 | 像原始时间戳 Literals 一样显示。 |
与当地时区的时间戳 | Instant | 1969-07-20 21:17:39 | 与原始时间戳 Literals 不同,但指的是同一 Moment。 |
时区时间戳 | OffsetDateTime | 1969 -07-20 16:17:39(UTC -04:00) | 与原始 Literals 一样显示,但也显示时区偏移。 |
当然,不同的语义不仅会影响文本表示形式,而且可能还会更重要地影响 SQL 函数的行为。这些允许用户以不同方式利用时间戳或显式创建不同的文本表示形式,而不是上面显示的隐式表示形式。
实际上,即使隐式文本表示形式也可能与上面所示的有所不同,例如,Instant 可以标准化显示为 UTC 或 OffsetDateTime 可以默认调整为本地时区。上面显示的示例只是为不同的语义创建隐式文本表示形式的常见方法,但 true 重要的区别在于可以从不同的语义中重构哪些细节以及不能重构哪些细节:
Reconstructible details | ||||
SQL type | Semantics | 本地时钟读取 | Time instant | 时区偏移 |
TIMESTAMP [WITHOUT TIME ZONE] | LocalDateTime | ✓ | ||
与当地时区的时间戳 | Instant | ✓ | ||
时区时间戳 | OffsetDateTime | ✓ | ✓ | ✓ |