ChatGPT解决这个技术问题 Extra ChatGPT

我应该在 MySQL 中使用 datetime 还是 timestamp 数据类型?

您是否推荐使用 datetimetimestamp 字段,为什么(使用 MySQL)?

我在服务器端使用 PHP。

如果您希望您的应用程序在 2038 年 2 月中断,请使用时间戳。检查日期范围。
如果您的数据库可能需要将值存储在不同时区或从不同时区的应用程序接收连接的可能性很小,请考虑对所有重要时间戳使用 ISO-8601 CHAR。看到这个问题:stackoverflow.com/questions/40670532/…

E
Eric Goerens

MySQL 中的时间戳一般用于跟踪记录的更改,并且经常在每次记录更改时更新。如果要存储特定值,则应使用日期时间字段。

如果您的意思是要在使用 UNIX 时间戳或原生 MySQL 日期时间字段之间做出决定,请使用原生 DATETIME 格式。您可以通过这种方式在 MySQL 中进行计算 ("SELECT DATE_ADD(my_datetime, INTERVAL 1 DAY)"),如果您想使用 PHP 对其进行操作,则在查询记录时可以很简单地将值的格式更改为 UNIX 时间戳 ("SELECT UNIX_TIMESTAMP(my_datetime)")


一个重要的区别是 DATETIME 表示日期(在日历中)和时间(可以在挂钟上观察到),而 TIMESTAMP 表示明确定义的时间点。如果您的应用程序处理时区,这可能非常重要。 '2010-09-01 16:31:00' 是多久以前的事了?这取决于您所在的时区。对我而言,这只是几秒钟前,对您而言,它可能代表未来的某个时间。如果我说自 '1970-01-01 00:00:00 UTC' 以来的 1283351460 秒,那么您确切知道我所说的时间点。 (请参阅下面 Nir 的出色回答)。 [缺点:有效范围]。
另一个区别:带有“本机”日期时间的查询不会被缓存,但带有时间戳的查询会被缓存。
“MySQL 中的时间戳通常用于跟踪记录的更改”不要认为这是一个好的答案。时间戳比 MattBianco 和 Nir 所说的要强大和复杂得多。虽然,答案的第二部分非常好。 blivet 说的是真的,是一个很好的建议。
我是支持 2000 的人:P
P
Peter Mortensen

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

默认情况下,每个连接的当前时区是服务器的时间。如MySQL Server Time Zone Support 中所述,可以基于每个连接设置时区。


这个 OReilly 演示文稿非常适合这个主题(PDF 抱歉)cdn.oreillystatic.com/en/assets/1/event/36/…
它还与事件的性质有关: - 视频会议 (TIMESTAMP)。所有服务员都应该看到对调整到其时区的绝对时间的引用。 - 本地任务时间(DATETIME),我应该在 2014 年 3 月 31 日上午 9:00 做这个任务,不管那天我在纽约还是巴黎工作。我将在当地时间上午 8:00 开始工作,我将在那天。
是的,这太可怕了。 DBMS 永远不应该在任何方向上转换时间戳,也不应该考虑当前 DB 的系统时间。它应该按原样保存内部时间戳(自纪元以来的毫秒数)。在呈现值时(在最后一刻),值应该在应用程序的用户时区中呈现(!)。其他一切都只是纯粹的痛苦。如果有的话,DBMS 应该支持本地和绝对时间的显式类型,其中“本地”类似于您的生日或“中午”,“绝对”类似于火箭的开始时间。
K
Kip

我总是将 DATETIME 字段用于除行元数据(创建或修改日期)之外的任何内容。

如 MySQL 文档中的 mentioned

当您需要包含日期和时间信息的值时,使用 DATETIME 类型。 MySQL 以 'YYYY-MM-DD HH:MM:SS' 格式检索和显示 DATETIME 值。支持的范围是“1000-01-01 00:00:00”到“9999-12-31 23:59:59”。 ... TIMESTAMP 数据类型的范围为 '1970-01-01 00:00:01' UTC 到 '2038-01-09 03:14:07' UTC。它具有不同的属性,具体取决于 MySQL 版本和服务器运行的 SQL 模式。

您很可能会达到一般使用的 TIMESTAMP 的下限——例如存储生日。


如果您从事银行业或房地产业,您也可以轻松达到上限... 30年抵押贷款现在超过2038年
当然,使用 64 位 Unix 时间戳。例如,在 Java 中,new Date().getTime() 已经为您提供了 64 位值。
不知道。这是一个比 MySQL 更大的问题并且没有简单的解决方法:en.wikipedia.org/wiki/Year_2038_problem 我不相信 MySQL 可以仅仅声明时间戳现在是 64 位并假设一切都会好起来的。他们不控制硬件。
所以 timestamp 在内部(大概)存储为 Unix 时间戳 - 一个整数。它可以快速插入和检索,但在对其应用日期函数时可能会更慢,因为它需要转换为内部日期时间格式才能执行此操作。因此,将 timestamp 用于简单的日志记录,它会很快,但不太灵活并且范围更小。
P
Peter Mortensen

以下示例显示了 TIMESTAMP 日期类型在更改 time-zone to 'america/new_york' 后如何更改值,其中 DATETIME 未更改。

mysql> show variables like '%time_zone%';
+------------------+---------------------+
| Variable_name    | Value               |
+------------------+---------------------+
| system_time_zone | India Standard Time |
| time_zone        | Asia/Calcutta       |
+------------------+---------------------+

mysql> create table datedemo(
    -> mydatetime datetime,
    -> mytimestamp timestamp
    -> );

mysql> insert into datedemo values ((now()),(now()));

mysql> select * from datedemo;
+---------------------+---------------------+
| mydatetime          | mytimestamp         |
+---------------------+---------------------+
| 2011-08-21 14:11:09 | 2011-08-21 14:11:09 |
+---------------------+---------------------+

mysql> set time_zone="america/new_york";

mysql> select * from datedemo;
+---------------------+---------------------+
| mydatetime          | mytimestamp         |
+---------------------+---------------------+
| 2011-08-21 14:11:09 | 2011-08-21 04:41:09 |
+---------------------+---------------------+

我已将我的答案转换成文章,以便更多人发现它有用,MySQL: Datetime Versus Timestamp Data Types


好吧,实际上 DATETIME 有效时间随着时区的变化而变化,TIMESTAMP 没有变化,但人类表示却发生了变化。
T
TRiG

主要区别在于 DATETIME 是常量,而 TIMESTAMP 受 time_zone 设置的影响。

因此,只有当您拥有(或将来可能拥有)跨时区同步集群时才重要。

简而言之:如果我在澳大利亚有一个数据库,并转储该数据库以同步/填充美国的数据库,则 TIMESTAMP 将更新以反映新时区中事件的实时时间,而 DATETIME 将仍然在 au 时区反映事件发生的时间。

在 Facebook 中应该使用 TIMESTAMP 的地方使用 DATETIME 的一个很好的例子,他们的服务器永远无法确定跨时区发生的时间。有一次我进行了一次对话,其中时间说我是在消息实际发送之前回复消息。 (当然,如果发布时间而不是同步时间,这也可能是由于消息传递软件中的时区转换错误造成的。)


我不认为这是一种好的思维方式。我只需以 UTC 格式存储和处理所有日期,并确保前端根据给定的时区显示它。这种方法简单且可预测。
@Kos:在UTC中存储和处理所有日期不正是TIMESTAMP在内部所做的吗? (然后将其转换为显示您当地的时区?)
我的本地时区?您的数据库如何知道我的时区? ;-) 数据库和用户界面之间通常有相当多的处理。我只在整个处理之后才进行本地化。
@Koz:我的数据库不知道您的数据库时区:!但它确实知道时间戳。您的数据库知道自己的时区设置,并在解释/表示时间戳时应用它。中国北京 2013 年 12 月 11 日凌晨 1:01 与澳大利亚悉尼 2013 年 12 月 11 日凌晨 1:01 的时间不同。谷歌:“时区”和“本初子午线”。
M
MaxVT

我在语义基础上做出这个决定。

当我需要记录(或多或少)固定时间点时,我会使用时间戳。例如,当一条记录插入数据库或发生某些用户操作时。

当可以任意设置和更改日期/时间时,我使用日期时间字段。例如,当用户可以保存以后更改约会时。


时间戳 - 固定时间点,协调世界时 datetime - 相对于某个观点,相对于时间参考(ej 时区本地时间),可能是.. 协调本地时间?
D
Daniel

我建议既不使用 DATETIME 也不使用 TIMESTAMP 字段。如果您想将特定的一天作为一个整体来表示(例如生日),请使用 DATE 类型,但如果您比这更具体,您可能对记录实际时刻而不是单位感兴趣时间(日、周、月、年)。不要使用 DATETIME 或 TIMESTAMP,而是使用 BIGINT,并简单地存储自纪元以来的毫秒数(如果您使用的是 Java,则为 System.currentTimeMillis())。这有几个优点:

您可以避免供应商锁定。几乎每个数据库都以相对相似的方式支持整数。假设您要移动到另一个数据库。您是否要担心 MySQL 的 DATETIME 值与 Oracle 如何定义它们之间的差异?即使在不同版本的 MySQL 中,TIMESTAMPS 也有不同的精度级别。直到最近,MySQL 才在时间戳中支持毫秒。没有时区问题。关于不同数据类型的时区会发生什么,这里有一些有见地的评论。但这是常识吗,你的同事都会花时间去学习吗?另一方面,很难将 BigINT 更改为 java.util.Date。使用 BIGINT 会导致时区出现很多问题。无需担心范围或精度。您不必担心未来日期范围会缩短什么时间(TIMESTAMP 只到 2038 年)。第三方工具集成。通过使用整数,第 3 方工具(例如 EclipseLink)与数据库的接口是微不足道的。并非每个第三方工具都会像 MySQL 那样对“日期时间”有相同的理解。如果您正在使用这些自定义数据类型,是否想尝试在 Hibernate 中确定是否应该使用 java.sql.TimeStamp 或 java.util.Date 对象?使用您的基本数据类型使得与 3rd-party 工具的使用变得微不足道。

这个问题与您应该如何在数据库中存储货币价值(即 1.99 美元)密切相关。您应该使用 Decimal,还是数据库的 Money 类型,或者最糟糕的是 Double?由于上面列出的许多相同原因,所有这 3 个选项都很糟糕。解决方案是使用 BIGINT 以美分存储货币的价值,然后在向用户显示价值时将美分转换为美元。数据库的工作是存储数据,而不是解释数据。您在数据库(尤其是 Oracle)中看到的所有这些花哨的数据类型几乎没有什么作用,并让您开始锁定供应商。


我喜欢这个解决方案。 2038 年到期的 TIMESTAMP 是一个主要问题。那真的不是那么遥远!
如果数据存储为毫秒数,则很难按日期查询数据
这应该是公认的答案。我鄙视任何一种“原生”日期格式。无尽的时区捕获等。
@Merc 不,不应该。数据结构中的语义是有原因的。数据库引擎具有语义类型也是有原因的。如果您根本不关心语义,为什么首先要使用 RDBMS(关系 -> 基于数据之间的语义关系)?
@lukasz032 是的,应该是。语义是一件好事,但是当您添加到混合时区、限制(2038 年有人吗?)、凌乱的实现和歧义时,那就不行了——现实世界的项目将使用 bigint 非常感谢
M
Mike

TIMESTAMP 是 4 个字节,而 DATETIME 是 8 个字节。数据库上的时间戳也更轻,索引速度更快。当您需要包含日期和时间信息的值时,使用 DATETIME 类型。 MySQL 以 YYYY-MM-DD HH:MM:SS 格式检索和显示 DATETIME 值。支持的范围是 1000-01-01 00:00:00 到 9999-12-31 23:59:59。 TIMESTAMP 数据类型的范围为 1970-01-01 00:00:01 UTC 到 2038-01-09 03:14:07 UTC。它具有不同的属性,具体取决于 MySQL 版本和服务器运行的 SQL 模式。DATETIME 是常量,而 TIMESTAMP 受 time_zone 设置的影响。


您需要澄清#4:存储的时间戳是恒定的并且与时区不相关(完全不可知),而检索时显示的输出受请求会话的时区影响。 DATETIME 始终与记录它的时区相关,并且必须始终在该上下文中考虑,现在属于应用程序的责任。
A
Alex

TIMESTAMP 是 4 个字节,而 DATETIME 是 8 个字节。

http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html

但是就像 scronide 说的那样,它确实有 1970 年的下限。不过,这对于未来可能发生的任何事情都很好;)


未来在 2038-01-19 03:14:07 UTC 结束。
i
ianaré

取决于应用程序,真的。

考虑为在桑海约会的用户设置一个时间戳到纽约的服务器。现在,当用户在 Sanghai 连接时,他从东京的镜像服务器访问相同的约会时间戳。他将在东京时间看到约会,与原来的纽约时间有偏差。

因此,对于代表用户时间的值(如约会或日程安排),日期时间更好。它允许用户控制所需的确切日期和时间,而不管服务器设置如何。设置时间是设置时间,不受服务器时区、用户时区或夏令时计算方式变化的影响(是的,它确实会改变)。

另一方面,对于表示系统时间的值,如支付交易、表修改或日志记录,始终使用时间戳。将服务器移动到另一个时区,或者在不同时区的服务器之间进行比较时,系统不会受到影响。

数据库上的时间戳也更轻,索引速度更快。


您的应用程序不应依赖服务器的时区。在发出任何查询之前,应用程序应始终在其使用的数据库连接会话中选择时区。如果在多个用户之间共享连接(例如:webapp),请使用 UTC 并在渲染端进行时区转换。
S
Sebastien Horin

2016 +:我建议将您的 Mysql 时区设置为 UTC 并使用 DATETIME:

任何最近的前端框架(Angular 1/2、react、Vue 等)都可以轻松自动地将您的 UTC 日期时间转换为本地时间。

此外:

DATETIME 现在可以自动设置为当前时间值 如何为 MySQL Datetime 列设置默认值?

与人们的想法相反,DATETIME 比 TIMESTAMP 更快,http://gpshumano.blogs.dri.pt/2009/07/06/mysql-datetime-vs-timestamp-vs-int-performance-and-benchmarking-with -myisam/

TIMESTAMP 仍然限于 1970-2038

(除非您可能会更改服务器的时区)

AngularJs 示例

// back-end: format for angular within the sql query
SELECT DATE_FORMAT(my_datetime, "%Y-%m-%dT%TZ")...

// font-end Output the localised time
{{item.my_datetime | date :'medium' }}

此处提供的所有本地化时间格式:https://docs.angularjs.org/api/ng/filter/date


您的数据不应附加到服务器的时区设置。也许,如果你的桌子下面有一个 MySql 盒子,它对你有用
W
William Entriken

两者都不。对于一般用例,DATETIMETIMESTAMP 类型根本不适用。 MySQL 将来会改变它们。您应该使用 BIGINT 和 UNIX 时间戳,除非您有特定的理由使用其他东西。

特别案例

以下是一些特定情况,您的选择更容易,您不需要此答案中的分析和一般建议。

仅日期 - 如果您只关心日期(例如下一个农历新年的日期,2022-02-01)并且您清楚地了解该日期适用的时区(或者不关心,如案例农历新年)然后使用 DATE 列类型。

记录插入时间——如果您正在记录数据库中行的插入日期/时间,并且您不关心您的应用程序将在未来 17 年内中断,那么请继续使用 TIMESTAMP 和默认值 CURRENT_TIMESTAMP()。

为什么 TIMESTAMP 坏了?

TIMESTAMP 类型以 UTC 时区存储在磁盘上。这意味着,如果您实际移动服务器,它不会中断。这很好✅。但目前定义的时间戳将在 2038 年完全停止工作❌。

每次您INSERT INTOSELECT FROM TIMESTAMP 列时,都会考虑您的客户端/应用程序服务器的物理位置(即时区配置)。如果您移动应用程序服务器,那么您的日期就会中断 ❌。

(2022 年 4 月 29 日更新 MySQL fixed this in 8.0.28,但如果您的生产环境使用 CentOS 7 或许多其他版本,那么您的迁移路径将需要很长时间才能获得此支持。)

为什么 VARCHAR 坏了?

VARCHAR 类型允许以 ISO 8601 格式明确存储非本地日期/时间/两者,并且适用于 2037 年之后的日期。通常使用 Zulu 时间,但 ISO 8601 允许对任何偏移量进行编码。这不太有用,因为虽然 MySQL 日期和时间函数确实支持字符串作为任何预期日期/时间/两者的输入,但如果输入使用时区偏移量,则结果不正确。

VARCHAR 还使用额外的存储字节。

为什么 DATETIME 坏了?

DATETIMEDATETIME 存储在同一列中。除非了解时区,否则这些事情都没有任何意义,并且时区不存储在任何地方❌。您应该将预期的时区作为注释放在列中,因为时区与数据有着千丝万缕的联系。很少有人使用专栏评论,因此这是等待发生的错误。我从亚利桑那州继承了一台服务器,因此我总是需要将所有时间戳从亚利桑那时间转换为另一个时间。

(更新 2021-12-08 我在运行多年后重新启动了服务器,并且数据库客户端(带有升级)重置为 UTC。这意味着我的应用程序需要以不同的方式处理重置前后的日期。硬编码!)

DATETIME 唯一正确的情况是完成这句话:

您的 2020 年太阳新年正好从 DATETIME("2020-01-01 00:00:00") 开始。

DATETIME 没有其他用途。也许您会想象特拉华州一个市政府的 Web 服务器。当然,这个服务器的时区和所有访问这个服务器的人都可以暗示在特拉华州,使用东部时区,对吧?错误的!在这个千禧年,我们都认为服务器存在于“云”中。因此,在任何特定时区考虑您的服务器总是错误的,因为您的服务器总有一天会被移动。

注意:MySQL 现在是 DATETIME 字面量 (thanks @Marko) 中的 supports time zone offsets。这可能使插入 DATETIME 对您来说更方便,但不能解决数据的不完整且因此无用的含义,这个致命问题在上面标识(“❌”)。

如何使用 BIGINT?

定义:

CREATE TEMPORARY TABLE good_times (
    a_time BIGINT
)

插入特定值:

INSERT INTO good_times VALUES (
    UNIX_TIMESTAMP(CONVERT_TZ("2014-12-03 12:24:54", '+00:00', @@global.time_zone))
);

或者当然这从您的应用程序中要好得多,例如:

$statement = $myDB->prepare('INSERT INTO good_times VALUES (?)');
$statement->execute([$someTime->getTimestamp()]);

选择:

SELECT a_time FROM good_times;

过滤相对时间的技术(选择过去 30 天内的帖子,查找在注册后 10 分钟内购买的用户)超出了这里的范围。


你的观点是 DATETIME 没有意义,除非时区被理解,但这并不会破坏它。您的应用程序代码应在将日期时间值插入数据库之前将其转换为所需的时区,因此在从数据库中检索该值时,您将知道它所在的时区。即使您的应用程序不关心时区,当应用程序的所有用户都在同一个时区时(例如应用程序仅在法国使用),就会出现这种情况。
@Marko 该参数同样适用于将日期时间值作为 VARCHAR 存储到数据库中:您的应用程序代码应在将值插入数据库之前将其转换为所需的格式。我的观点是,数据库是用来存储数据的,包括该数据有意义所需的所有上下文。
这是一个应用于 ISO 8601 VARCHAR 值的 MySQL 内置函数:SELECT DATE_ADD("2020-01-01", INTERVAL 2 DAY)。这是一个应用 ISO 8601 VARCHARs 的 MySQL 内置日期比较运算符:SELECT "2020-01-01" < "2020-03-01"
我还是不明白这一点。如果您以 UTC 存储任何日期,并以 UTC 运行所有服务器,则您对数据有清晰的了解。因此,您可以将日期作为 2022-01-23T09:59:56+00:00 提供给客户,他们可以根据用户的时区应用格式。我在这里想念什么?
因为某些数据库管理员无法完全控制他们的应用程序在哪个服务器上运行。也许您的数据库被发送回 QA/DEV 并且他们有不同的时区,事情就会中断。我在 UTC-8 时区有一台服务器,一切都很好。但是当它重新启动时,它突然变成了 UTC。我在那里有 root 访问权限,这个变化是出乎意料的。使用 BIGINT 永远不会中断。
d
dolmen

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

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


H
Hafenkranich

timestamp 字段是 datetime 字段的特例。您可以创建 timestamp 列以具有特殊属性;它可以设置为在创建和/或更新时更新自身。

在“更大”的数据库术语中,timestamp 上有几个特殊情况的触发器。

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


不,区别不仅仅是“特例”。因为设置/查询值的会话的时区涉及不同。
N
Nuran

DATETIME、TIMESTAMP 和 DATE 之间的比较

https://i.stack.imgur.com/ANc33.png

那 [.fraction] 是什么?

DATETIME 或 TIMESTAMP 值可以包括以微秒(6 位)精度为单位的尾随小数秒部分。特别是,插入到 DATETIME 或 TIMESTAMP 列中的值中的任何小数部分都会被存储而不是被丢弃。这当然是可选的。

资料来源:

MySQL 日期/时间数据类型参考

MySQL 存储要求参考


P
Peter Mortensen

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

on update CURRENT_TIMESTAMP

这将更新您修改行的每个实例的时间,有时对于存储的最后编辑信息非常有帮助。这仅适用于时间戳,但不适用于日期时间。


H
HoldOffHunger

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

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


-1 我实际上认为下面的答案更好 - 使用 datetime 允许您将更多用于日期处理的逻辑推送到 MySQL 本身,这可能非常有用。
没有基准表明 MySQL 中的排序比 php 中的排序慢吗?
好吧,这取决于,有时当我们不想使用 strtotime 时使用它会很好。 (php5.3 开发)
如果需要,您可以仅使用 FROM_UNIXTIME 将逻辑推送到 mysql
我曾经在我的 PHP 应用程序和 MySQL 中使用所有 Unix 时间戳,但是我发现在 MySQL 中将日期和时间存储为本地日期/时间类型要方便得多。这对于报告目的和浏览数据集特别有用。随着时间的推移,当我不得不复制/过去的 Unix 时间戳感到沮丧时,我开始切换。我很确定有性能和其他优点/缺点,但根据您的用例便利性可能比相当微的优化更重要。
P
Peter Mortensen

根据我的经验,如果您想要一个仅插入一次的日期字段,并且您不想对该特定字段进行任何更新或任何其他操作,请使用日期时间。

例如,考虑一个具有 REGISTRATION DATE 字段的 user 表。在该 user 表中,如果您想知道特定用户的上次登录时间,请使用 timestamp 类型的字段,以便更新该字段。

如果您从 phpMyAdmin 创建表,则默认设置将在发生行更新时更新 timestamp 字段。如果您的时间戳文件没有随着行更新而更新,您可以使用以下查询来使 timestamp 字段自动更新。

ALTER TABLE your_table
      MODIFY COLUMN ts_activity TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

P
Peter Mortensen

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

因此,假设您在美国并从具有美国时区的服务器获取数据。然后您将根据美国时区获得日期和时间。时间戳数据类型列总是在其行更新时自动更新。因此,跟踪上次更新特定行的时间会很有用。

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


您可以(应该)始终使用 SET time_zone = '+0:00';(此处为 UTC)在会话级别定义时区,以确保您从 TIMESTAMP 值获取/设置什么,并避免依赖于可能会更改的服务器 time_zone 默认值。
P
Peter Mortensen

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

另一件值得考虑的事情:

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


A
Anvesh

Reference taken from this Article:

主要区别:

TIMESTAMP 用于跟踪记录的更改,并在每次记录更改时更新。 DATETIME 用于存储不受记录更改影响的特定静态值。

TIMESTAMP 也受不同 TIME ZONE 相关设置的影响。 DATETIME 是常数。

TIMESTAMP 在内部将当前时区转换为 UTC 进行存储,并在检索期间转换回当前时区。 DATETIME 不能这样做。

TIMESTAMP 支持范围:'1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC DATETIME 支持范围:'1000-01-01 00:00:00' 到 '9999 -12-31 23:59:59'


R
Roger Campanera

就我而言,我每次都将 UTC 设置为所有内容的时区:系统、数据库服务器等。如果我的客户需要另一个时区,那么我会在应用程序上对其进行配置。

我几乎总是更喜欢时间戳而不是日期时间字段,因为时间戳隐含地包含时区。因此,由于来自不同时区的用户将访问应用程序并且您希望他们查看其本地时区的日期和时间,因此与将数据保存在日期时间字段中相比,此字段类型更容易做到.

另外,在将数据库迁移到具有另一个时区的系统的情况下,我会更有信心使用时间戳。更不用说在计算两个时刻之间的差异时可能存在的问题,并且两者之间的总和时间变化并且需要 1 小时或更短的精度。

所以,总而言之,我看重时间戳的这个优点:

准备在国际(多时区)应用程序上使用

时区之间的轻松迁移

很容易计算差异(只需减去两个时间戳)

不用担心夏季时间段的日期

出于所有这些原因,我尽可能选择 UTC 和时间戳字段。而且我避免头痛;)


当 2038 年 1 月 20 日到来时,时间戳数据对于支持您的申请的人来说会很有趣。滴答滴答
然后可以将时间戳类型增加一点并将可能的值加倍。
测试您的理论以“增加一点”,看看您是否可以成功存储 2038 年 2 月 1 日并使用 MySQL 检索它。完成后让我们看看你的表定义。 2038 年 2 月,你可能会有很多不开心的过去熟人。
@WilsonHauck 无论如何,您都必须在 2038 年之前升级 MySQL 版本。并且扩展的 TIMESTAMP 将由迁移处理。此外,除了处理抵押贷款之外,很少有应用程序现在真正需要关心 2038 年。
@dolmen 许多专业级工具和材料都有 20 年以上的保修期。所以像 warranties.expires_at 这样的东西今天不可能是 MySQL 时间戳。
L
Lloyd Banks

当您对表执行 UPDATE 语句时,请注意时间戳更改。如果您有一个包含 'Name' (varchar)、'Age' (int) 和 'Date_Added' (timestamp) 列的表,并且您运行以下 DML 语句

UPDATE table
SET age = 30

那么“Date_Added”列中的每个值都将更改为当前时间戳。


根据您设置表格的方式,您可以控制此行为。看看dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
@CharlesFaiga 默认行为是在更新任何其他列时更新时间戳。如果您希望时间戳保留其原始值,则必须明确关闭此功能
那是什么 ?!您必须将 timstamp 列设置为 ON UPDATE CURRENT_TIMESTAMP
这是您在创建表时必须明确启用的功能。
P
Premraj
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
|                                       TIMESTAMP                                       |                                 DATETIME                                 |
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
| TIMESTAMP requires 4 bytes.                                                           | DATETIME requires 8 bytes.                                               |
| Timestamp is the number of seconds that have elapsed since January 1, 1970 00:00 UTC. | DATETIME is a text displays 'YYYY-MM-DD HH:MM:SS' format.                |
| TIMESTAMP supported range: ‘1970-01-01 00:00:01′ UTC to ‘2038-01-19 03:14:07′ UTC.    | DATETIME supported range: ‘1000-01-01 00:00:00′ to ‘9999-12-31 23:59:59′ |
| TIMESTAMP during retrieval converted back to the current time zone.                   | DATETIME can not do this.                                                |
| TIMESTAMP is used mostly for metadata i.e. row created/modified and audit purpose.    | DATETIME is used mostly for user-data.                                   |
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+

P
Peter Mortensen

我发现 TIMESTAMP 能够根据当前时间自动更新自身而无需使用不必要的触发器,这一点非常有用。但这只是我,尽管 TIMESTAMP 就像人们所说的那样是 UTC。

它可以跨不同时区跟踪,因此如果您需要显示相对时间,例如,UTC 时间就是您想要的。


R
Rahul Kr Daman

日期时间与时间戳:

TIMESTAMP 用于跟踪记录的变化,并在每次记录发生变化时更新。

DATETIME 用于存储不受记录更改影响的特定静态值。

TIMESTAMP 也受不同 TIME ZONE 相关设置的影响。 DATETIME 是常数。

TIMESTAMP 在内部将当前时区转换为 UTC 进行存储,并在检索期间将其转换回当前时区。

DATETIME 不能这样做。

TIMESTAMP 为 4 个字节,DATETIME 为 8 个字节。

TIMESTAMP 支持范围:'1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC DATETIME 支持范围:'1000-01-01 00:00:00' 到 '9999 -12-31 23:59:59'


C
Community

主要区别在于

时间戳上的索引 - 有效

日期时间的索引 - 不起作用

看看这个post to see problems with Datetime indexing


如果您使用基于列值的函数进行选择,则两者都有相同的问题,并且两者都可以被索引。
索引适用于时间戳,不适用于日期时间?您从这些帖子中得出了错误的结论。
A
Accountant م

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

当你问什么时候?答案类似于'2019-02-05 21:18:30',没有完成,没有定义答案,因为它缺少另一部分,在哪个时区?华盛顿?莫斯科?北京 ?

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

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

为了让您的客户感到舒适,您希望根据他们喜欢的时区向他们展示时间,而不是让他们进行数学运算并将时间转换为他们有意义的时区。您只需要更改时区,所有应用程序代码都将相同。(实际上,您应该始终在应用程序开始时定义时区,或者在 PHP 应用程序的情况下请求处理) SET time_zone = '+2:00 ';您更改了您所在的国家/地区,并继续维护数据,同时在不同的时区查看数据(不更改实际数据)。您接受来自世界各地不同客户的数据,他们每个人都在他的时区插入时间。

简而言之

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

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

这个答案只是为了强调时间戳在时区方面的灵活性和易用性,它没有涵盖像 column size or range or fraction 这样的任何其他差异。


如果在一个表中存在使用 date 的字段,而其他字段使用 timestamp 怎么办。我认为这会导致一个新的问题,因为 where 过滤的数据不符合时区更改。
@ErlangP 在这种情况下,您的应用程序应该在发送查询之前修复 date 列上的时区问题。
e
ecleel

Timestamp 和 Datetime 之间的另一个区别是 Timestamp 您不能将默认值设置为 NULL。


这显然是错误的。 Here is an example: CREATE TABLE t2 ( ts1 TIMESTAMP NULL, ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP); 第一列可以接受 NULL 值。
H
Hans

我更喜欢使用时间戳,以便将所有内容保持在一种通用的原始格式中,并在 PHP 代码或 SQL 查询中格式化数据。在某些情况下,它可以在您的代码中派上用场,让一切都在几秒钟内完成。