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

Should I use the datetime or timestamp data type in MySQL?

提问人:Gad 提问时间:1/4/2009 最后编辑:Damjan PavlicaGad 更新时间:10/21/2023 访问量:1112048

问:

您是否建议使用日期时间或时间戳字段,为什么(使用 MySQL)?

我在服务器端使用 PHP。

mysql 日期时间 时间戳 sqldatatypes

评论

2赞 Waqleh 7/26/2018
这有一些相关信息 codeproject.com/Tips/1215635/MySQL-DATETIME-vs-TIMESTAMP
9赞 Wilson Hauck 3/12/2020
如果您希望您的应用程序在 2038 年 2 月被破坏,请使用时间戳。检查日期范围。
0赞 Alex R 9/20/2020
如果您的数据库可能需要在不同的时区存储值或从不同时区的应用程序接收连接,请考虑将 ISO-8601 CHAR 用于所有重要的时间戳。看这个问题:stackoverflow.com/questions/40670532/...
0赞 Fattie 10/10/2022
datetime 是完全没用的。这只是一个愚蠢的字符串。时间戳在各个方面都是完美的,但它在 2038 年结束。

答:

27赞 Mark Davidson 1/4/2009 #1

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

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

评论

8赞 Toby Hede 1/4/2009
-1 我实际上认为下面的答案更好 - 使用 datetime 可以让您将更多日期处理逻辑推送到 MySQL 本身,这可能非常有用。
0赞 sdkfasldf 5/17/2010
难道没有基准测试表明MySQL中的排序比php中的排序慢吗?
0赞 Adam Ramadhan 9/2/2010
嗯,这取决于,有时当我们不想使用 strtotime 时使用它是件好事。( php5.3 dep )
0赞 inarilo 5/25/2017
如果需要,只需使用 FROM_UNIXTIME 即可将逻辑推送到 MySQL 中
0赞 DavidScherer 5/12/2018
我曾经在我的PHP应用程序和MySQL中使用所有Unix时间戳,但是我发现在MySQL中将日期和时间存储为本机日期/时间类型要方便得多。这对于报告目的和仅浏览数据集特别有用。随着时间的流逝,当我不得不复制/粘贴 Unix 时间戳时感到沮丧时,我开始切换。我很确定有性能和其他优点/缺点,但根据您的用例,便利性可能比相当微观的优化更重要。
42赞 Jeff Warnica 1/4/2009 #2

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

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

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

评论

8赞 dolmen 1/19/2016
不,区别不仅仅是“特例”。由于设置/查询值的会话的时区涉及不同。
2112赞 blivet 1/4/2009 #3

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

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

此外,从 MySQL 8.0.19 开始,它支持时区偏移,因此现在使用的理由更少了。DATETIMETIMESTAMP

评论

1170赞 MattBianco 9/1/2010
一个重要的区别是,它表示日期(如日历中所示)和时间(如挂钟上所示),而表示明确定义的时间点。如果您的应用程序处理时区,这可能非常重要。'2010-09-01 16:31:00'是多久以前?这取决于您所在的时区。对我来说,这只是几秒钟前,对你来说,它可能代表着未来的某个时间。如果我说自“1970-01-01 00:00:00 UTC”以来的 1283351460 秒,你确切地知道我说的是哪个时间点。(请参阅下面 Nir 的出色回答)。[缺点:有效范围]。DATETIMETIMESTAMP
140赞 OZ_ 4/29/2011
另一个区别是:带有“native”datetime 的查询不会被缓存,但带有 timestamp - 的查询将被缓存。
58赞 santiagobasulto 5/16/2011
“MySQL中的时间戳通常用于跟踪记录的更改” 不要认为这是一个好的答案。正如 MattBianco 和 Nir 所说,时间戳比这强大得多,也复杂得多。虽然,答案的第二部分非常好。布利维特说的是真的,这是一个很好的建议。
4赞 Fattie 10/10/2022
这个答案在各个方面都是完全错误的。
2赞 Charles Wood 10/7/2023
@Fattie 你能说得更具体一点吗?或者也许提供你自己的答案?
144赞 unbeknown 1/4/2009 #4

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

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

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

评论

0赞 yucer 12/17/2013
timestamp- 固定时间点,协调世界时 datetime - 相对于一个观点,相对于时间参考(ej 时区当地时间),可以是。协调当地时间?
609赞 scronide 1/4/2009 #5

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

如MySQL文档中所述

当您需要同时包含日期和时间信息的值时,将使用 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 的下限 - 例如存储出生日期。

评论

238赞 Kip 8/10/2012
如果您在银行或房地产行业,您也可以轻松达到上限......30 年期抵押贷款现在超过 2038 年
22赞 Sergey Orshanskiy 10/8/2013
当然,请使用 64 位 Unix 时间戳。例如,在 Java 中,已经为您提供了 64 位值。new Date().getTime()
14赞 scronide 2/11/2015
不知道。这是一个比MySQL大得多的问题,而且没有简单的解决方法:en.wikipedia.org/wiki/Year_2038_problem 我不相信MySQL可以声明时间戳现在是64位,并假设一切都会好起来的。他们不控制硬件。
0赞 Jason 4/19/2022
所以在内部(大概)存储为 Unix 时间戳 - 一个整数。它的插入和检索速度很快,但在对其应用日期功能时可能会变慢,因为它需要转换为内部日期时间格式才能执行此操作。因此,用于简单的日志记录,它会很快,但灵活性较差且范围较小。timestamptimestamp
8赞 Hans 1/4/2009 #6

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

111赞 Alex 1/4/2009 #7

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

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

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

评论

220赞 MattBianco 9/1/2010
未来将在 2038-01-19 03:14:07 UTC 结束。
1赞 TeasingDart 6/14/2023
对于在 64 位平台上运行的 MySQL 8.0.28 及更高版本,UNIX_TIMESTAMP() 的有效参数值范围为 '1970-01-01 00:00:01.000000' UTC 到 '3001-01-19 03:14:07.9999999' UTC(对应于 32536771199.9999999 秒)。
1051赞 Nir 3/2/2009 #8

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

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

评论

15赞 gcb 10/27/2013
这个 OReilly 演示文稿非常适合这个主题(PDF 对不起)cdn.oreillystatic.com/en/assets/1/event/36/......
21赞 yucer 12/17/2013
它还与事件的性质有关: - 视频会议 (TIMESTAMP)。所有与会者都应看到对根据其时区调整的绝对时刻时间的引用。- 本地任务时间(DATETIME),我应该在 2014 年 3 月 31 日上午 9:00 完成此任务,无论那天我是在纽约还是巴黎工作。我将在当天当地时间上午 8:00 开始工作。
0赞 spyro 11/12/2021
是的,这太可怕了。DBMS 永远不应该在任何方向上转换时间戳,也不应该考虑当前数据库的系统时间。它应该只按原样保存内部时间戳(自 epoch 以来的毫秒)。呈现值时(在最后一刻),应从应用程序以用户的时区显示 (!) 值。其他一切都只是纯粹的痛苦。如果有的话,DBMS 应该支持本地时间和绝对时间的显式类型,其中“本地”类似于您的生日或“中午”,“绝对”类似于火箭的开始时间。
223赞 ekerner 1/14/2010 #9

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

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

简单来说:如果我在澳大利亚有一个数据库,并转储该数据库以同步/填充美国的数据库,那么 TIMESTAMP 将更新以反映新时区中事件的实时时间,而 DATETIME 仍将反映澳大利亚时区中的事件时间

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

评论

105赞 Kos 3/3/2012
我不认为这是一种好的思维方式。我只是以UTC格式存储和处理所有日期,并确保前端根据给定的时区显示它。这种方法简单且可预测。
10赞 carbocation 12/9/2013
@Kos:以UTC格式存储和处理所有日期不是TIMESTAMP在内部所做的吗?(然后将其转换为显示您的本地时区?
12赞 Kos 12/9/2013
我的本地时区?您的数据库如何知道我的时区?;-)数据库和用户界面之间通常会进行相当多的处理。我只在整个处理后进行本地化。
5赞 ekerner 12/10/2013
@Koz:我的数据库不知道你的数据库时区:!但它确实知道时间戳。您的数据库知道自己的时区设置,并在解释/表示时间戳时应用该设置。2013年12月11日凌晨1:01,中国北京,与2013年12月11日凌晨1:01,澳大利亚悉尼不同。谷歌:“时区”和“本初子午线”。
1赞 ysth 5/24/2023
是的,TIMESTAMP 有效地以 UTC 格式存储(有限范围)时间。但随后有效地向你隐藏了它。强烈建议仅使用 datetime 并仅存储 UTC,并避免使用连接时区的所有函数(now、current_date、unix_timestamp 等)。
43赞 Sobes 8/26/2010 #10

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

注意:默认连接时区是服务器时区,但可以(应该)根据会话进行更改(请参阅)。SET time_zone = ...

54赞 ianaré 10/27/2010 #11

真的取决于应用程序。

考虑将用户的时间戳设置为纽约的服务器,以便在 Sanghai 进行约会。现在,当用户在 Sanghai 中连接时,他会从东京的镜像服务器访问相同的约会时间戳。他将在东京时间看到约会,与原来的纽约时间相抵消。

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

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

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

评论

0赞 dolmen 5/22/2019
应用程序不应依赖于服务器的时区。在发出任何查询之前,应用程序应始终选择其使用的数据库连接会话中的时区。如果连接在多个用户(例如:webapp)之间共享,请使用 UTC 并在呈现端执行时区转换。
6赞 user723220 4/29/2011 #12

我喜欢 Unix 时间戳,因为您可以转换为数字,而只担心数字。另外,您还可以添加/减去并获取持续时间等。然后将结果转换为任何格式的日期。此代码计算文档中的时间戳与当前时间之间经过的时间(以分钟为单位)。

$date  = $item['pubdate']; (etc ...)
$unix_now = time();
$result = strtotime($date, $unix_now);
$unix_diff_min = (($unix_now  - $result) / 60);
$min = round($unix_diff_min);

评论

4赞 Julien Palard 4/25/2013
或者,使用人类可读的原生MySQL日期时间,并使用原生MySQL函数来添加/减去日期时间。
374赞 Vishwanath Dalvi 8/21/2011 #13

以下示例显示了日期类型在更改位置不变后如何更改值。TIMESTAMPtime-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:日期时间与时间戳数据类型

评论

83赞 flindeberg 7/4/2014
嗯,实际上有效时间随着时区的变化而变化,没有改变,但人类的表示却发生了变化。DATETIMETIMESTAMP
12赞 Marc DiMillo 11/2/2011 #14

我发现 TIMESTAMP 能够根据当前时间自动更新自己,而无需使用不必要的触发器,这是无与伦比的实用性。不过这只是我,尽管 TIMESTAMP 就像人们所说的那样是 UTC。

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

16赞 Oliver Holmberg 1/5/2012 #15

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

另一件值得考虑的事情:

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

29赞 leejmurphy 1/7/2012 #16

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

on update CURRENT_TIMESTAMP

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

20赞 Kannan Prasad 2/6/2012 #17

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

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

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

ALTER TABLE your_table
      MODIFY COLUMN ts_activity TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
17赞 Arvind 12/20/2012 #18

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

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

有关更多详细信息,您可以阅读博客文章 时间戳与日期时间

评论

0赞 dolmen 10/9/2019
您可以(应该)始终使用(此处为 UTC)在会话级别定义时区,以确保从值中获取/设置的内容,并避免依赖于服务器time_zone默认值,这可能会发生变化。SET time_zone = '+0:00';TIMESTAMP
16赞 Lloyd Banks 10/4/2013 #19

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

UPDATE table
SET age = 30

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

评论

4赞 Charles Faiga 3/7/2014
根据您设置表的方式,您可以控制此行为。看看 dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
6赞 Lloyd Banks 3/9/2014
@CharlesFaiga 默认行为是时间戳在任何其他列更新时更新。如果希望时间戳保留其原始值,则必须显式关闭此功能
0赞 Accountant م 9/3/2019
什么?!必须将 timstamp 列设置为ON UPDATE CURRENT_TIMESTAMP
0赞 dolmen 10/9/2019
这是创建表时必须显式启用的功能
0赞 user2648008 9/3/2023
我很幸运能读到这个答案
140赞 Vivek S 12/21/2013 #20
  1. TIMESTAMP是 4 个字节,而 是 8 个字节。DATETIME

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

  3. 当您需要同时包含日期和时间信息的值时,将使用该类型。MySQL检索并以格式显示值。支持的范围是 。数据类型的范围为 to。它具有不同的属性,具体取决于MySQL版本和服务器运行的SQL模式。DATETIMEDATETIMEYYYY-MM-DD HH:MM:SS1000-01-01 00:00:009999-12-31 23:59:59TIMESTAMP1970-01-01 00:00:01 UTC2038-01-09 03:14:07 UTC

  4. DATETIME是恒定的,而受设置的影响。TIMESTAMPtime_zone

评论

18赞 Christopher McGowan 1/28/2016
您需要澄清 #4:存储的时间戳是恒定的,与时区无关(完全不可知),而检索时显示的输出受请求会话的时区影响。DATETIME 始终与记录它的时区相关,并且必须始终在该上下文中考虑,现在该责任落在应用程序身上。
9赞 ecleel 1/19/2014 #21

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

评论

8赞 Ormoz 4/28/2015
这显然是错误的。下面是一个示例: 第一列可以接受 NULL 值。CREATE TABLE t2 ( ts1 TIMESTAMP NULL, ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
10赞 Charles Faiga 3/7/2014 #22

主要区别在于

  • 时间戳上的索引 - 有效
  • 日期时间的索引 - 不起作用

看看这篇文章,看看日期时间索引的问题

评论

6赞 Marcus Adams 2/20/2015
如果使用基于列值的函数进行选择,则两者都存在相同的问题,并且两者都可以编制索引。
4赞 Salman A 3/3/2015
索引在时间戳上起作用,在日期时间上不起作用?你从这些帖子中得出了错误的结论。
136赞 user64141 6/12/2014 #23

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

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

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

评论

17赞 Charlie Dalsass 5/13/2015
我喜欢这个解决方案。TIMESTAMP 在 2038 年到期是一个主要问题。那不是很遥远!
22赞 Ali Saeed 12/21/2015
如果数据存储为毫秒数,则很难按日期查询数据
1赞 Merc 8/11/2021
这应该是公认的答案。我鄙视任何一种“原生”日期格式。无尽的时区捕获等。
2赞 Lukasz032 1/7/2022
@Merc不,不应该。数据结构中的语义有原因的。数据库引擎具有语义类型也是有原因的。如果你根本不关心语义,为什么首先要使用RDBMS(基于数据之间语义关系的关系->)呢?
0赞 Merc 1/8/2022
@lukasz032是的,它应该是。语义是一件好事,但是当你在混合时区、限制(2038 年有人吗?)、混乱的实现和歧义时,那么不——现实世界的项目会使用 bigint 非常感谢
16赞 Anvesh 2/7/2016 #24

参考资料摘自本文:

主要区别:

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'

52赞 Sebastien Horin 2/18/2016 #25

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

评论

10赞 Jin 5/6/2016
您的数据不应附加到服务器的时区设置中。也许,如果你的办公桌下有一个MySql盒子,它对你有用
3赞 Martin Zeitler 5/23/2016 #26

我只是在存储UTC时使用unsigned ...BIGINT

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

要用 选择。DATETIMEFROM_UNIXTIME( integer_timestamp_column )

显然应该在该列上设置索引,否则就没有进展。

7赞 Mwangi Thiga 6/23/2016 #27

A 需要 4 个字节,而 A 需要 8 个字节。TIMESTAMPDATETIME

评论

1赞 virtualeyes 2/13/2022
“从 MySQL 5.6.4 开始,YEAR 和 DATE 的存储保持不变。然而。。。DATETIME 的打包效率更高,需要 5 个字节而不是 8 个字节“,因此 timestamp 和 datetime 之间相差 1 个字节,时间戳在 2038 年”到期“即将到来:)来自文档:dev.mysql.com/doc/refman/8.0/en/...
3赞 Matthew 6/28/2016 #28

这里的很多答案都建议存储为时间戳,以防您必须表示定义明确的时间点。但是,如果按照惯例将它们全部存储在 UTC 中,则也可以具有日期时间的时间点。

评论

0赞 Jasir 8/12/2016
你能给出一些理由为什么我应该更喜欢这个而不是使用时间戳吗?
3赞 Matthew 8/12/2016
@Jasir不是真的,这似乎是一场大辩论。我只是指出,如果存在将所有日期时间存储在特定时区(即 UTC)中的约定,则日期时间可以表示特定的时间点。就个人而言,我会将所有内容存储在 datetime 中,时间戳限制为 2038 年(尽管我猜他们最终会对此做些什么),如果我查看数据库中的一些原始数据,datetime 将是可读的,而无需应用转换。同样,这是非常主观的。
0赞 dolmen 10/9/2019
@Matthew 但是,如果会话不是,如果您使用MySQL日期/时间函数(例如,而不先转换时区),则会遇到意外(错误)...那么,为什么要让数据库交互变得比必要的更复杂呢?time_zoneUTCNOW()DATE_ADD
1赞 Matthew 10/10/2019
@dolmen的想法是,服务器端的一切都是UTC。包括 MySQL 会话时区。这应该设置为服务器的时区,应为 UTC
6赞 Mahdi Jazini 10/27/2016 #29

当您有来自不同国家/地区和不同时区的访客时,TIMESTAMP 很有用。您可以轻松地将 TIMESTAMP 转换为任何国家/地区的时区

3赞 Elliptical view 11/4/2016 #30

到目前为止没有提到的是 DEFAULT CURRENT_TIMESTAMP仅适用于 Timestamp,而不适用于 DateTime 类型字段。

这与只能使用 DateTime 而不能使用 Timestamp 的 MS Access 表相关。

评论

9赞 Sarath Sadasivan Pillai 3/27/2017
MySQL 5.6 中添加了对 a 的支持。DEFAULT CURRENT_TIMESTAMPDATETIME
1赞 CPHPython 4/26/2018
“的任何同义词都具有与 相同的含义。这些是 和 .“ -> mysql 文档CURRENT_TIMESTAMPCURRENT_TIMESTAMPCURRENT_TIMESTAMP(), NOW(), LOCALTIME, LOCALTIME(), LOCALTIMESTAMPLOCALTIMESTAMP()
16赞 Roger Campanera 2/25/2017 #31

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

我几乎总是更喜欢时间戳而不是日期时间字段,因为时间戳隐含了时区。因此,从来自不同时区的用户访问应用程序的那一刻起,您希望他们以本地时区查看日期和时间,因此与将数据保存在日期时间字段中相比,此字段类型非常容易做到这一点。

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

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

  • 在国际(多时区)应用程序上随时可用
  • 在时区之间轻松迁移
  • 计算差异非常容易(只需减去两个时间戳)
  • 无需担心夏季期间的日期

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

评论

0赞 Wilson Hauck 5/10/2019
当 2038 年 1 月 20 日到来时,时间戳数据对于支持您的应用程序的人来说会很有趣。嘀嗒嘀嗒
0赞 Roger Campanera 7/2/2019
然后,时间戳类型可以增加一点,并使可能的值增加一倍。
0赞 Wilson Hauck 7/3/2019
测试你的理论以“增加一点”,看看你是否能成功存储 2038 年 2 月 1 日并使用 MySQL 检索它。完成后,让我们看看您的表定义。在2038年2月,你可能会有很多不快乐的过去熟人。
2赞 dolmen 10/9/2019
@WilsonHauck无论如何,您必须在 2038 年之前很久就升级 MySQL 版本。扩展的 TIMESTAMP 将由迁移处理。此外,除了处理抵押贷款之外,现在很少有申请真正需要关心 2038 年。
0赞 alexw 5/26/2020
@dolmen许多专业级工具和材料都有 20+ 年保修。因此,今天不可能是MySQL时间戳。warranties.expires_at
36赞 Dehan 8/11/2017 #32

DATETIME、TIMESTAMP 和 DATE 之间的比较

enter image description here

[.fraction]是什么?

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

来源:

14赞 Premraj 4/12/2018 #33
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
|                                       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.                                   |
+---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
0赞 curiosity 6/30/2018 #34

timestamp是计算机通过网络时间协议 (NTP) 记录的事件的当前时间。

datetime是在 PHP 配置中设置的当前时区。

评论

0赞 dolmen 10/9/2019
不。与 NTP 无关。
10赞 Accountant م 2/6/2019 #35

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

当你问几点了?答案是“2019-02-05 21:18:30”,没有完成,没有定义的答案,因为它缺少另一部分,在哪个时区?华盛顿?莫斯科?北京?

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

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

  1. 为了让您的客户感到舒适,您希望根据他们喜欢的时区向他们展示时间,而不是让他们进行数学计算并将时间转换为他们有意义的时区。您只需更改时区,所有应用程序代码都将相同。(实际上,您应该始终在应用程序开始时定义时区,或者在PHP应用程序的情况下定义请求处理)

    SET time_zone = '+2:00';
    
  2. 您更改了您所在的国家/地区,并继续维护数据的工作,同时在不同的时区查看数据(不更改实际数据)。

  3. 您接受来自世界各地不同客户的数据,每个客户都在他的时区中插入时间。

总之

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

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


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

评论

0赞 Erlang Parasu 2/11/2020
如果一个表中有使用 的字段和其他字段使用,该怎么办?我认为这会引起一个新问题,因为过滤的数据不符合时区变化。datetimestampwhere
0赞 Accountant م 2/11/2020
@ErlangP在这种情况下,应用程序应在发送查询之前修复列上的时区问题。date
0赞 Wilson Hauck 3/29/2019 #36

如果你想保证你的应用程序在 2038 年 2 月不会运行,请使用 TIMESTAMP。有关支持的日期范围,请参阅您的 REFMAN。

评论

0赞 dolmen 10/9/2019
到目前为止,2038 年您早已将 MySQL 服务器版本更改为支持扩展 TIMESTAMP 的版本。这也假设您的应用程序仍在使用中。
5赞 Booboo 9/3/2019 #37

A 不携带任何时区信息,并且将始终显示相同的时区信息,而与会话生效的时区无关,除非您明确更改了时区,否则默认为服务器的时区。但是,如果我使用诸如 之类的函数而不是诸如 之类的文字来初始化列,那么存储的值当然将是本地化为会话时区的当前日期和时间。DATETIMEDATETIMENOW()'2020-01-16 12:15:00'

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

何时使用其中之一?案例研究

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

另一方面,一旦 2019 年 12 月 12 日晚上 8 点的演出开始,我们可能不再想出售它的门票,因此不再在下拉列表中显示该表演。因此,我们希望能够知道“2019-12-12 20:00:00”是否发生。这将主张有一个列,将会话的时区设置为“美国/New_York”,然后存储到列中。此后,我们可以通过将此列与独立于当前会话时区的进行比较来测试性能是否已经开始。TIMESTAMPset session time_zone='America/New_York''2019-12-12 20:00:00'TIMESTAMPNOW()

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

评论

0赞 dolmen 10/9/2019
对于TIMESTAMP值以及MySQL日期/时间函数来说,重要的不是服务器,而是会话(在显式更改之前默认为服务器)。切勿在应用中依赖可能更改的默认值。time_zonetime_zonetime_zone
0赞 Booboo 10/9/2019
@dolmen 当然,你是对的,但我们谈论的是语义。我在回答中说,也许可以通过说“设置会话的时区”来更清楚地表达,但最终这将是服务器将使用的时区。我将更新答案以使其更清楚。"... setting the the server's timezone for the session ...".
65赞 William Entriken 12/24/2019 #38

也不。对于通用用例,DATETIMETIMESTAMP 类型从根本上被破坏了。MySQL将来会改变它们。您应该使用 BIGINT 和 UNIX 时间戳,除非您有特定原因需要使用其他东西。

特殊情况

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

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

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

为什么坏了?TIMESTAMP

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

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

(更新 2022-04-29:MySQL 在 8.0.28 中修复了此问题,但如果您的生产环境在 CentOS 7 或许多其他版本上,您的迁移路径将需要很长时间才能获得此支持。

为什么坏了?VARCHAR

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

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

为什么坏了?DATETIME

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

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

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

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

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

注意:MySQL现在支持文字中的时区偏移感谢@Marko)。这可能会使插入 s 对您来说更方便,但并不能解决数据的不完整且因此无用的含义,这个致命的问题在上面标识了 (“❌”)。DATETIMEDATETIME

如何使用?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))
);

插入默认值(谢谢布拉德):

ALTER TABLE good_times MODIFY a_time BIGINT DEFAULT (UNIX_TIMESTAMP());

或者,当然,这对您的应用程序来说要好得多,例如:

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

选择:

SELECT a_time FROM good_times;

有一些技术可以过滤超出此处范围的相对时间(选择过去 30 天内的帖子,查找在注册后 10 分钟内购买的用户)。

评论

1赞 William Entriken 8/25/2020
@Marko,该参数同样适用于将 datetime 值存储到数据库中,作为 : 应用程序代码应在插入数据库之前将值转换为所需的格式。我的观点是,数据库是用来存储数据的,包括使该数据具有意义所需的所有上下文。VARCHAR
1赞 William Entriken 9/3/2020
以下是应用于 ISO 8601 值的 MySQL 内置函数: 。下面是一个应用ISO 8601的MySQL内置日期比较运算符:VARCHARSELECT DATE_ADD("2020-01-01", INTERVAL 2 DAY)VARCHARSELECT "2020-01-01" < "2020-03-01"
3赞 Moritz Friedrich 1/23/2022
我仍然不明白这有什么意义。如果以 UTC 格式存储任何日期,并以 UTC 运行所有服务器,则对数据有清晰的了解。因此,您可以将日期作为 提供给客户端,并且他们可以根据用户的时区应用格式。我在这里错过了什么?2022-01-23T09:59:56+00:00
1赞 William Entriken 1/24/2022
因为某些数据库管理员无法完全控制其应用程序在哪个服务器上运行。也许你的数据库被发送回 QA/DEV,他们有不同的时区,事情就坏了。我在 UTC-8 时区有一台服务器,一切都很好。但是当它重新启动时,它突然变成了UTC。我在那里有root访问权限,这种变化是出乎意料的。使用永不中断。BIGINT
1赞 Brad 10/26/2022
这是给你的提示,bigint 的自动流派时间戳。我一直在为此苦苦挣扎,发现 mysql 8 允许您在周围添加额外的内容时将其用作默认值。我认为,如果你加上这个,真的会完成答案。unix_timestamp()()
12赞 Rahul Kr Daman 12/29/2019 #39

日期时间与时间戳:

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'

1赞 Javier G.Raya 4/2/2022 #40

DATETIME 类型用于包含日期和时间部分的值。MySQL以格式检索并显示DATETIME值。支持的范围是 。'YYYYYY-MM-DD hh:mm:ss' '1000-01-01 00:00:00''9999-12-31 23:59:59'

TIMESTAMP 数据类型用于包含日期和时间部分的值。TIMESTAMP 的范围从 '1970-01-01 00:00:01'UTC 到 '2038-01-19 03:14:07'UTC。

mysql> SELECT col,
     >     CAST(col AT TIME ZONE INTERVAL '+00:00' AS DATETIME) AS ut
     >     FROM ts ORDER BY id;
+---------------------+---------------------+
| col                 | ut                  |
+---------------------+---------------------+
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2019-12-31 23:40:10 | 2020-01-01 04:40:10 |
| 2020-01-01 13:10:10 | 2020-01-01 18:10:10 |
| 2020-01-01 10:10:10 | 2020-01-01 15:10:10 |
| 2020-01-01 04:40:10 | 2020-01-01 09:40:10 |
| 2020-01-01 18:10:10 | 2020-01-01 23:10:10 |
+---------------------+---------------------+

URL MySQL 8.0:https://dev.mysql.com/doc/refman/8.0/en/datetime.html