您建议使用datetime或timestamp字段吗?为什么(使用MySQL)?

我在服务器端使用PHP。


当前回答

在MySQL 5及以上版本中,TIMESTAMP值从当前时区转换为UTC进行存储,并从UTC转换回当前时区进行检索。(这仅适用于TIMESTAMP数据类型,而不适用于DATETIME等其他类型。)

默认情况下,每个连接的当前时区是服务器的时间。可以根据每个连接设置时区,如MySQL Server时区支持中所述。

其他回答

我总是使用Unix时间戳,只是为了在处理大量日期时间信息时保持理智,尤其是在调整时区、添加/减去日期等时。在比较时间戳时,这排除了时区的复杂因素,并允许您在服务器端处理(无论是应用程序代码还是数据库查询)中节省资源,因为您使用了较轻的算术,而不是较重的日期时间加减函数。

另一件值得考虑的事情:

如果您正在构建一个应用程序,那么您永远不知道您的数据可能会被如何使用。如果你最终不得不将数据集中的一堆记录与第三方API中的一堆项目进行比较,然后按照时间顺序排列,你会很高兴为你的行设置Unix时间戳。即使您决定使用MySQL时间戳,也要存储Unix时间戳作为保险。

时间戳字段是datetime字段的特殊情况。您可以创建具有特殊财产的时间戳列;它可以设置为在创建和/或更新时更新自己。

在“更大”的数据库术语中,时间戳有两个特殊的情况触发器。

正确的答案完全取决于你想做什么。

在使用MySQL和PHP时,我总是使用Unix时间戳。这主要是因为PHP中的默认日期方法使用时间戳作为参数,因此不需要解析。

要获取PHP中当前的Unix时间戳,只需执行time();在MySQL中执行SELECT UNIX_TIMESTAMP();。

DATETIME不携带时区信息,并且将始终显示与会话有效的时区无关的时区,除非您明确更改它,否则默认为服务器的时区。但是,如果我使用NOW()之类的函数而不是“2020-01-16 12:15:00”之类的文字来初始化DATETIME列,是本地化到会话时区的当前日期和时间。

相比之下,TIMESTAMP确实隐式地携带时区信息:当您使用值初始化TIMESTAMP列时,该值在存储之前会转换为UTC。如果存储的值是文本,例如“2020-01-16 12:15:00”,则出于转换目的,它被解释为在会话的当前时区中。相反,当显示TIMESTAMP列时,它将首先从UTC转换为会话的当前时区。

什么时候使用一个或另一个?案例研究

一个社区剧团的网站正在播放几场正在售票的戏剧演出。这些演出的日期和时间将显示在下拉列表中,希望购买演出门票的客户将从中选择一个。数据库列performance_date_and_time为DATETIME类型是有意义的。如果演出地点在纽约,则有一种理解,即有一个隐含的时区(“纽约当地时间”),理想情况下,我们希望日期和时间显示为“2019年12月12日晚上8点”,而不考虑会议的时区,也不必麻烦进行任何时区转换。

另一方面,一旦2019年12月12日晚上8点的演出开始,我们可能不再想出售门票,因此不再在下拉列表中显示该演出。因此,我们想知道“2019-12-12 20:00:00”是否已发生。这将证明有一个TIMESTAMP列,将会话的时区设置为“America/New_York”,并将会话time_zone设置为“American/New_约克”,然后将“2019-12-12 20:00:00”存储到TIMESTAMP栏中。从此,我们可以通过独立于当前会话时区将此列与NOW()进行比较来测试性能是否已开始。

或者,为这两个单独的目的设置DATETIME和TIMESTAMP列可能是有意义的。或者不是。显然,任何一个都可以达到这两个目的。如果只使用DATETIME列,则在与NOW()进行比较之前,必须将当前时区设置为本地时区。如果只使用TIMESTAMP列,则必须在显示该列之前将会话时区设置为本地时区。

TIMESTAMP始终采用UTC格式(即自1970-01-01以来的秒数,采用UTC格式),MySQL服务器会自动将其转换为连接时区的日期/时间。从长远来看,TIMESTAMP是一条可行的道路,因为您知道您的时间数据将始终采用UTC格式。例如,如果您迁移到其他服务器或更改服务器上的时区设置,您就不会把日期搞砸。

注意:默认连接时区是服务器时区,但这可以(应该)在每个会话中更改(请参见SET time_zone=…)。