使用TIMESTAMP WITHTIME TIME ZONE的有效用例是什么?


40

关于两者之间的区别,有一个很长很清楚的答案

  • TIMESTAMP WITH TIME ZONE -vs-
  • TIMESTAMP WITHOUT TIME ZONE

在此SO帖子中可用。我想知道的是:是否存在任何实际使用的有效用例,TIMESTAMP WITHOUT TIME ZONE或者应该将其视为反模式。


这个问题冒着被“主要基于意见”封闭的风险。我在下面的回答中尝试给出一些客观的观点。
Colin't Hart 2014年

2
这个问题是很现实的,每种数据类型都有不同的含义。因此,我当然不会认为这个问题主要是基于观点的。
罗勒·布尔克

Answers:


29

这在很多地方说,但我认为这值得一提的总是当我们比较timestamp with time zonetimestamp without time zone类型:timestamp WITH time zone不将存储时区与时间戳一起信息。它所做的是将所有数据存储在UTC时区中,如docs中所述

对于带时区的时间戳,内部存储的值始终以UTC(通用协调时间,通常称为格林威治标准时间,GMT)表示。使用该时区的适当偏移量,将指定了明确时区的输入值转换为UTC。如果在输入字符串中未指定时区,则假定该时区位于系统的TimeZone参数指示的时区中,并使用时区时区的偏移量转换为UTC。

在某些timestamp WITHOUT time zone情况下(1)一切都在同一时区或(2)应用程序层处理时区并仅将所有内容存储在某个时区(通常是UTC)中,这种方法被认为对某些人有效。但这也被认为是一种反模式,因为(1)的正确解决方案是将TimeZone设置配置为系统的给定时区,并且(2)已解决,因为PostgreSQL已将所有内容存储在同一时区(世界标准时间)。

现在,有了这两个功能,我只有一个很好的理由来使用timestamp WITHOUT time zone。那是您将来要存储事件的时间,到那时我们必须触发某种警报。timestamp WITH time zone如果且仅当该地区的有关时区的法律所定义的规则从未改变时,这可能是有益的。更改的最常见规则是关于是否采用日光节约时间(DST)。

例如,假设您正在2013-06-15(尚未在DST中)安排某个事件发生的时间2013-01-15 10:00(该事件已经在DST中发生),并且2013-06-15指定您所在的地区采用DST;但是在那之后的一段时间,政府更改了规则,并说您所在的地区将不再使用DST,如果您使用,并保持TZ配置最新,则您的计划时间突然变成2013-01-15 11:00(而不是10:00timestamp WITH time zone。当然,如果您跟踪自己感兴趣的地区/时区中的规则更改并更新受影响的记录,那么您可能还会注意到也可以使用时区来处理此类情况。

值得一提的是,某些地区的确会经常更改这些规则(例如在巴西,某些州-而不是整个国家-经常会更改),但在大多数情况下,更改的时间很早,因此您的用户只会受到距离很远的活动的影响当前时间。

话虽如此,我只有一个建议。如果您确实在不同时区有用户,日志或其他任何内容,请存储他们来自某个地方的时区,然后选择并使用timestamp with time zone。这样,您可以(1)针对不同来源(与时区无关)相互交叉发生事件,并且(2)显示事件发生的原始时间(时钟时间)。


您说的是:“我只有一​​个很好的理由来使用带时区的时间戳”。如果那不是错别字,那么您是否确实建议“无时区的时间戳”实际上比“有时区的时间戳”更合适/更容易产生误解?这对我来说似乎违反直觉。
Marcus Junius Brutus 2014年

@MarcusJuniusBrutus,对此感到抱歉,这确实是一个错字,我想反过来...检查编辑后的答案。
MatheusOl 2014年

codeblog.jonskeet.uk/2019/03/27/…深入讨论了这个未来事件规则-可能发生变化的场景(具有相同的结论)
Beni Cherniavsky-Paskin

17

是。有一些用例TIMESTAMP WITHOUT TIME ZONE

  • 在常见的商业应用中,此类型仅用于:
    • 预约未来的约会
    • 代表各个时区的同一时间,例如东京巴黎的23日正午(相差两个小时,同一时间)
  • 要跟踪时刻(时间轴上的特定点),请始终使用TIMESTAMP WITH TIME ZONE而不是WITHOUT

TIMESTAMP WITHOUT TIME ZONE不是时间轴上的一点,不是实际时刻。它们代表了有关潜在时刻的粗略想法,可能涉及时间轴上大约26-27小时(全球时区范围)内的时间点。在您应用时区UTC偏移之前,它们没有真正的意义。

例如:圣诞节

例如,假设您需要记录假期/圣日的开始。

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

要记录圣诞节在今年12月25日午夜之后开始的事实,我们需要说不2016-12-25 00:00:00带任何时区。圣诞老人那天凌晨,他在午夜之后访问NZ奥克兰,因为这是全球最早的午夜之一。然后,随着下一个午夜的到来,他向西行驶,不久便到达了菲律宾。然后,驯鹿向西方向移动,在午夜到达印度,恰好发生在奥克兰午夜后的几个小时。更晚之后仍是巴黎FR的午夜,再晚仍是加利福尼亚州蒙特利尔的午夜。圣诞老人的所有这些拜访都是在不同的时间发生的,但是每个地点都在午夜后不久发生,具体时间取决于每个地方的午夜。

因此2016-12-25 00:00:00,在圣诞节开始时没有任何时区的录音内容丰富,合法,但模糊不清。在您说“奥克兰的圣诞节”或“蒙特利尔的圣诞节”之前,我们没有特定的时间。如果您每次记录雪橇降落时都在记录实际时刻,则应使用TIMESTAMP WITH TIME ZONE而不是WITHOUT类型。

与圣诞节相似的是除夕。当纽约时代广场舞会落下时,西雅图的人们仍在冷藏香槟,准备派对喇叭。然而,我们将记录的想法新年的时刻,作为2017-01-01 00:00:00一个TIMESTAMP WITHOUT TIME ZONE。相反,如果我们想记录何时纽约落下球,或者西雅图人何时鸣喇叭,我们将使用TIMESTAMP WITH TIME ZONE(而不是WITHOUT)记录这些实际时刻,彼此间隔三个小时。

例如:工厂班次

另一个示例可能是记录涉及不同位置的挂钟时间的策略。假设我们在底特律,杜塞尔多夫和德里都有工厂。如果我们说在所有三个工厂中,第一个班次从上午6点开始,在上午11:30午餐休息,则可以记录为TIMESTAMP WITHOUT TIME ZONE。同样,此信息以模糊的方式很有用,但在我们应用时区之前不会指示特定的时刻。东方较新的一天到来了。因此,德里工厂将是第一个早上6点开放的工厂。几个小时后,杜塞尔多夫工厂在早上6点开始工作。但是底特律工厂要等到六个小时后才早上6点才真正开业。

将这个想法(关于通常何时开始工厂倒班)与每个工厂工人何时开始在特定一天开始倒班的历史事实进行对比。计时是一个真实的时刻,是时间轴上的实际点。因此,我们会将其记录在type列中,TIMESTAMP WITH TIME ZONE而不是WITHOUTtype中。

因此,是的,存在合法的用例TIMESTAMP WITHOUT TIME ZONE。但是根据我在商务应用程序方面的经验,它们相对很少见。在业务中,我们倾向于关心实际时刻:发票何时真正到达,合同何时确切生效,银行交易何时执行。因此,在这种常见情况下,我们需要TIMESTAMP WITH TIME ZONE类型。

有关更多讨论,请参见对类似问题的答案我应该存储UTC时间戳还是本地时间以进行轮班

Postgres

请注意,Postgres特别是从不保存插入时间戳时指定的时区信息。

  • TIMESTAMP WITH TIME ZONE
    • 输入数据中包含的任何指定时区或偏移量都用于将值调整为UTC并存储。然后,传递的区域/偏移信息将被丢弃。认为TIMESTAMP WITH TIME ZONETIMESTAMP WITH RESPECT FOR TIME ZONE
    • 印度今年3月7日中午12:00的输入将通过减去五个半小时(上午6:30)将其时间调整为UTC。
  • TIMESTAMP WITHOUT TIME ZONE
    • 输入数据中包含的任何指定时区或偏移都将被完全忽略。
    • 印度今年3月7日中午12:00的输入被记录为今年3月7日中午12:00,没有进行任何调整。

SQL标准几乎没有涉及日期时间数据类型和行为的问题。因此,数据库在处理日期时间方面差异很大


进一步出厂(或医院)的变化,任何工作DST转换的天夜班都会有它的记录不正确时区记录了他们的时间..
贾森

我认为这是在最后一个例子一个错字:“中午12:00的3月7日的输入..应该是‘记录为12:00’(未21:00
TmTron

11

我想为此添加另一种观点,这与其他答案中的大部分内容背道而驰。我认为timestamp with time zone几乎没有有效的用例,timestamp without time zone因此通常应优先使用。

首先,您必须了解“无处不在的UTC”模式,通常建议对没有特殊要求的所有应用程序使用该模式。这仅表示您的应用程序应始终无时无刻地以UTC表示其所有时间戳。当然,您将向用户显示本地日期/时间,但是其想法是在渲染视图时在程序的最边缘转换它们。这是将UTC时间戳(您可能已从数据库加载)和用户时区(可能来自浏览器)组合到本地时间戳的正确位置。

如果您遵循此模式,timestamp with time zone则为反模式。这种类型的作用是使PostgreSQL在读取和写入时间戳时根据您的PostgreSQL TimeZone会话变量执行时区转换。您没有在应用程序的最边缘处理时区,而是将它们引入了它的核心,并与数据库进行了通信。您必须注意始终始终TimeZone正确配置PostgreSQL ,这会增加另一个不必要的失败和混乱点。

为了什么 如果您遵循UTC无处不在模式,则您的应用程序无论如何都只有UTC时间戳。那么,为什么要让您的数据库对它们进行时区转换呢?您可以简单地将它们存储在timestamp without time zone列中,并像对待UTC一样对待它。没有转换,没有时区,没有并发症。


2
我认为时间戳的支持者也支持“无处不在的UTC”模式。只是规则只是在数据库级别强制执行,而不是仅依靠应用程序/ API开发人员来强制执行它?如果您能够执行该做法,为什么不呢?另外,您可以强制所有postgres连接将其时区设置为UTC。即使没有,ISO格式也会包含tz偏移量。难道不是所有地方都强制执行UTC吗?
iamnat

3
首先,如果您的PostgreSQL时区设置为UTC以外的任何值,并且您使用的是时间戳,则您的程序正在读取非UTC时间戳。这根本不是“无处不在的UTC”模式,并且取决于您的客户语言可能会也可能不会带来很多麻烦。无论你是UTC无处不在,或者你正在使用本地时间戳....
吉文Rojansky

其次,再一次,如果您在应用程序中的任何地方都使用UTC,那么时间戳就没有以ISO格式发送的tz偏移量。具体细节将因语言而异,但是理想情况下,您应该使用无法代表UTC时间戳(例如InstanceNodaTime / JodaTime中的时间戳)的客户端类型。您基本上是在描述几乎要遵循“无处不在的UTC”的情况,或者有点遵循的情况
Shay Rojansky

再一次,很容易想象在某个服务器上设置了新的PostgreSQL实例,而意外保留了默认配置的本地计算机时区。应用程序从该服务器读取并在完全任意的时区(服务器恰好位于该时区)中获取本地时间戳。我们为什么要这种额外的并发症?
Shay Rojansky

1
可以,但是使用起来就没有意义了timestamptz。这种类型的重点是执行时区转换,作为对PostgreSQL进行读写的值(在数据库内部,时间戳始终保存为UTC)。始终将会话时区设置为UTC会有效地禁用这些转换,那么为什么要使用它timestamptz呢?换句话说,如果数据库中的值是UTC,而进出数据库的值始终是UTC,那么为什么数据库中根本没有时区意识?
谢伊·罗

2

date时间戳也没有包括时区信息,但有很多人使用它。

当然,这本身并不是答案。

它的有效使用timestampdate任何时间戳和日期,它总是在同一个时区,或在相对于一些已知的时区存储。

如果时区始终相同或隐式,则存储时区要比不存储时区更重要(冗余信息)。

时间戳还可用于存储技术信息,例如在应用程序日志中使用的信息或用于性能测量的信息。在这种情况下,时区也可能不重要。


相反,如果您正在设计或在分布式系统上或在其中系统的各个部分分布在不同时区的任何系统中工作,则可以将其视为不使用的反模式timestamp with timezone,尽管某些系统可能被设计为可以运行在一个时区,例如UTC。在这种情况下,时区逻辑可能会被推到应用程序层中-但我认为这是一种反模式,是的。


我了解在某些情况下使用它不会带来伤害timestamp without timezone,但是它能为我买任何东西吗?否则,如果timestamp with timezone data类型总是相等或更合适,为什么还要打扰呢?
Marcus Junius Brutus 2014年

不存储冗余信息将是我的主要论点。我猜想日期运算timestamp without timezone也会更快,但这仅在您要处理数十亿行时才重要……
Colin't Hart

1
@ Colin'tHart timestamptimestamptz都以相同的方式存储。中没有存储任何时区信息timestamptz,而是将其转换为UTC进行存储。我要说的是,始终timestamptz在有关时间戳表示绝对时间时使用。这就是全部timestamptz。我已经在这里写过这个。
fphilipe

2

如果您的应用程序限于一个时区,则似乎很想在本地时间存储和处理日期/时间,但是我认为这是一个错误。

当从夏令时切换回标准时间时,将重复本地时间的一小时(假设时差为一小时)。我住的地方通常发生在凌晨2点左右,因此本地时间运行在01:58、01:59、01:00,并且在重复的小时结束时才前进到02:00。

如果您尝试使用本地时间按时间排序事件,则意味着两个小时内的事件混合在一起,并且不会按照实际发生的顺序显示。

相比之下,UTC则没有此问题,订单整齐。因此,即使仅使用一个时区,您也希望数据库以UTC存储和处理时间,并转换为本地时间或从本地时间转换为输入/显示。这是TIMESTAMP WITH TIME ZONE的行为。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.