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

我在服务器端使用PHP。


当前回答

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列,则必须在显示该列之前将会话时区设置为本地时区。

其他回答

在遇到许多与时区相关的问题和错误后,我停止在应用程序中使用datetime。在大多数情况下,IMHO使用时间戳优于datetime。

当你问什么时候?答案类似于“2019-02-05 21:18:30”,这不是完整的,也不是定义的答案,因为它缺少另一部分,在哪个时区?华盛顿?莫斯科北京?

使用不带时区的日期时间意味着您的应用程序只处理一个时区,但时间戳为您提供了日期时间的好处,以及在不同时区显示相同精确时间点的灵活性。

以下是一些会让您后悔使用datetime并希望将数据存储在时间戳中的情况。

为了客户的舒适,您希望根据他们首选的时区向他们显示时间,而不让他们做数学运算,并将时间转换为有意义的时区。您只需更改时区,所有应用程序代码都将相同。(实际上,您应该始终在应用程序开始时定义时区,或者在PHP应用程序中定义请求处理)SET time_zone=“+2:00”;您改变了所居住的国家,并继续维护数据,同时在不同的时区查看数据(而不更改实际数据)。您接受来自世界各地不同客户的数据,每个客户都会在自己的时区中插入时间。

简言之

datetime=应用程序支持1个时区(用于插入和选择)

timestamp=应用程序支持任何时区(用于插入和选择)


这个答案只是为了强调时区的灵活性和易用性,它没有涵盖任何其他差异,如列大小、范围或分数。

我更喜欢使用时间戳,以便将所有内容保持在一个通用的原始格式中,并将数据格式化为PHP代码或SQL查询。在某些情况下,它可以在代码中方便地将所有内容保持在简单的秒数内。

值得注意的是,在MySQL中,您可以在创建表列时使用以下内容:

on update CURRENT_TIMESTAMP

这将更新每次修改行时的时间,有时对存储的上次编辑信息非常有用。这只适用于时间戳,但不适用于日期时间。

时间戳数据类型存储日期和时间,但使用UTC格式,而不是像datetime那样使用当前时区格式。当您获取数据时,时间戳再次将其转换为当前时区时间。

所以假设你在美国,从一个时区为美国的服务器获取数据,然后你将根据美国时区获取日期和时间。时间戳数据类型列总是在其行更新时自动更新。因此,跟踪上次更新特定行的时间可能很有用。

有关更多详细信息,您可以阅读博客文章Timestamp Vs Datetime。

我只在存储UTC时使用无符号BIGINT。。。

然后仍然可以在PHP中将其调整为本地时间。

要使用FROM_UNIXTIME(integer_timestamp_column)选择的DATETIME。

显然,应该在该列上设置索引,否则不会有任何进展。