我应该在mysql中使用datetime或timestamp数据类型吗?

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

您是否建议使用datetime或timestamp字段,以及为什么(使用mysql)?

我正在服务器端使用PHP。


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

如果您想决定使用unix时间戳还是本机mysql日期时间字段,请使用本机格式。你可以用这种方式在MySQL中进行计算("SELECT DATE_ADD(my_datetime, INTERVAL 1 DAY)")并且在查询记录时,如果要使用php对其进行操作,很容易将值的格式更改为unix时间戳("SELECT UNIX_TIMESTAMP(my_datetime)")


在MySQL5及以上版本中,时间戳值从当前时区转换为用于存储的UTC,然后从UTC转换回当前时区进行检索。(这仅适用于timestamp数据类型,而不适用于其他类型,如datetime。)

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


除了行元数据(创建或修改日期),我总是使用日期时间字段。

如MySQL文档中所述:

The DATETIME type is used when you need values that contain both date and time information. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.

...

The TIMESTAMP data type has a range of '1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' UTC. It has varying properties, depending on the MySQL version and the SQL mode the server is running in.

在一般情况下,您很可能会达到时间戳的下限——例如存储生日。


下面的示例显示了在DATETIME不变的情况下,TIMESTAMP日期类型在更改time-zone to 'america/new_york'之后如何更改值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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和timestamp数据类型。


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

因此,只有当您已经或将来可能已经跨时区同步集群时,这才重要。

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

在Facebook中,使用时间戳的一个很好的例子就是使用日期时间戳,在Facebook中,他们的服务器永远无法确定跨时区发生了什么时间事件。有一次,我正在进行一次谈话,在谈话中,时间说我是在回复消息之前才真正发送消息。(当然,如果发布时间而不是同步时间,这也可能是由于消息传递软件中的时区转换错误造成的。)


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

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

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


我建议既不要使用日期时间字段也不要使用时间戳字段。如果你想代表一个特定的一天作为一个整体(比如生日),那么使用日期类型,但是如果你比这更具体,你可能会有兴趣记录一个实际的时刻,而不是一个时间单位(天、周、月、年)。使用DigeTimes或时间戳,而不是使用BigIt,只需存储EPOCH(System .CurrnTimeMILISH())中的毫秒数,如果您使用Java)。这有几个优点:

  • 避免供应商锁定。几乎每个数据库都以相对相似的方式支持整数。假设您想移动到另一个数据库。是否要担心MySQL的日期时间值之间的差异以及Oracle如何定义它们?即使在不同版本的MySQL中,时间戳的精度也不同。仅在最近,MySQL才支持时间戳中的毫秒数。
  • 没有时区问题。对于不同数据类型的时区,这里有一些有见地的评论。但这是常识吗?你的同事会花时间学习吗?另一方面,很难把bigint改成java.util.date。使用bigint会导致很多时区问题的发生。
  • 无需担心范围或精度。您不必担心未来日期范围会缩短哪些时间(时间戳仅限于2038)。
  • 第三方工具集成。通过使用整数,第三方工具(例如EclipseLink)与数据库进行交互非常简单。并不是每一个第三方工具都能像MySQL那样理解"日期时间"。想要在Hibernate中尝试找出是否应该使用java.sql.timestamp或java.util.date对象(如果使用这些自定义数据类型)?使用基本数据类型使得与第三方工具的使用变得简单。
  • 这个问题与如何在数据库中存储货币值(即1.99美元)密切相关。您应该使用十进制,还是数据库的货币类型,或者最糟糕的是使用双精度?所有3个选项都很糟糕,原因与上面列出的许多相同。解决方案是使用bigint将货币值存储为美分,然后在向用户显示值时将美分转换为美元。数据库的工作是存储数据,而不是重复这些数据。您在数据库(尤其是Oracle)中看到的所有这些花哨的数据类型都没有增加什么,这会让您踏上供应商锁定的道路。


    时间戳是4个字节,而datetime是8个字节。

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

    但正如斯克里德所说,它确实有一个1970年的下限。不过,它对将来可能发生的任何事情都很有帮助;)


  • 时间戳是4个字节,而datetime是8个字节。

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

  • 当需要同时包含日期和时间信息的值时,将使用日期时间类型。MySQL检索并以"yyyy-mm-dd hh:mm:ss"格式显示日期时间值。支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。

  • 时间戳数据类型的范围是'1970-01-01 00:00:01'UTC到'2038-01-09 03:14:07'UTC。它有不同的属性,这取决于MySQL版本和服务器运行的SQL模式。

  • 日期时间是常量,而时间戳受时区设置的影响。

  • 这真的取决于应用程序。

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

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

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

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


    2016+:我建议您将MySQL时区设置为UTC并使用日期时间:

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

    另外:

    • 现在可以自动将datetime设置为当前时间值。如何为mysql datetime列设置默认值?
    • 与人们想象的相反,日期时间比时间戳快,http://gpshumano.blogs.dri.pt/2009/07/06/mysql-datetime-vs-timestamp-vs-int-performance-and-benchmarking-with-myisam/
    • 时间戳仍限于1970-2038年

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

    AngularJS示例

    1
    2
    3
    4
    5
    // 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/日期


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

    在"更大"的数据库术语中,timestamp有几个特殊的案例触发器。

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


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


    日期时间、时间戳和日期之间的比较

    enter image description here

    那是什么[分数]?

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

    资料来源:

    • mysql日期/时间数据类型引用
    • MySQL存储需求参考


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

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


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

    要在php中获取当前的unix时间戳,只需执行EDOCX1[0]在mysql中做SELECT UNIX_TIMESTAMP();


    根据我的经验,如果您想要一个日期字段,其中插入只发生一次,并且您不希望在该特定字段上有任何更新或任何其他操作,请使用日期时间。

    例如,考虑一个带有注册日期字段的user表。在该user表中,如果您想知道特定用户最后一次登录的时间,请使用timestamp类型的字段,以便更新该字段。

    如果从phpmyadmin创建表,则当行更新时,默认设置将更新时间戳字段。如果时间戳文件没有使用行更新进行更新,则可以使用以下查询使时间戳字段自动更新。


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

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

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


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

    另一件值得考虑的事情是:

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


    本文引用:

    主要区别:

    用于跟踪记录更改并在每次更改记录时更新的时间戳。用于存储特定值和静态值的日期时间,这些值不受记录中任何更改的影响。

    时间戳还受不同时区相关设置的影响。日期时间是常量。

    时间戳在内部将当前时区转换为用于存储的UTC,并在检索期间转换回当前时区。日期时间不能这样做。

    时间戳支持的范围:'1970-01-01 00:00:01'UTC到'2038-01-19 03:14:07'UTC日期时间支持的范围:'1000-01-01 00:00:00'至'9999-12-31 23:59:59'


    在表上执行UPDATE语句时,注意时间戳的更改。如果您有一个列为'name'(varchar)、'age'(int)和'date_added'(timestamp)的表,则运行以下DML语句

    1
    2
    UPDATE table
    SET age = 30

    然后,"添加日期"列中的每个值都将更改为当前时间戳。


    在我的例子中,我将UTC设置为所有东西的时区:系统、数据库服务器等,每次我都可以。如果我的客户需要另一个时区,那么我会在应用程序中对其进行配置。

    我几乎总是喜欢时间戳而不是日期时间字段,因为时间戳隐式地包含时区。因此,由于从不同时区的用户访问应用程序的那一刻起,您希望他们在本地时区中查看日期和时间,因此与将数据保存在日期时间字段中相比,此字段类型使得执行此操作非常容易。

    另外,如果将数据库迁移到具有另一个时区的系统,我会更加自信地使用时间戳。在计算两个时刻之间的差异时,不要说可能的问题,因为在这两个时刻之间的时间变化比较短,需要1小时或更短的精度。

    因此,总的来说,我看重时间戳的优点:

    • 可在国际(多时区)应用程序上使用
    • 在时区之间轻松迁移
    • 很容易计算差异(只需减去两个时间戳)
    • 不用担心夏天的约会

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


    timestamp和datetime的另一个区别是timestamp,不能将值默认为空。


    主要区别是

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

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


    我发现时间戳在不使用不必要的触发器的情况下根据当前时间自动更新自身的能力中具有无与伦比的有用性。虽然时间戳和上面说的一样是UTC,但那只是我。

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


    1
    2
    3
    4
    5
    6
    7
    8
    9
    +---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+
    |                                       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 to2038-01-19 03:14:07′ UTC.    | DATETIME supported range: ‘1000-01-01 00:00:00to9999-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.                                   |
    +---------------------------------------------------------------------------------------+--------------------------------------------------------------------------+

    我更喜欢使用时间戳,以便将所有内容保持为一种常见的原始格式,并以PHP代码或SQL查询格式设置数据。在某些情况下,在代码中,它可以很方便地将所有内容保持在几秒钟之内。


    我喜欢unix时间戳,因为您可以将其转换为数字,只需担心数字。再加上加/减和获取持续时间等,然后以任何格式将结果转换为日期。此代码找出从文档传递时间戳到当前时间之间的时间(分钟)。

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


    TIMESTAMP需要4个字节,而DATETIME需要8个字节。


    到目前为止还没有提到,默认的当前时间戳只适用于时间戳,而不适用于日期时间类型字段。

    这与只能使用日期时间而不能使用时间戳的MS Access表相关。


    当您有来自不同国家、不同时区的访客时,时间戳非常有用。您可以轻松地将时间戳转换为任何国家/地区时区


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

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

    FROM_UNIXTIME( integer_timestamp_column )选择DATETIME

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


    这里有很多答案建议将其存储为时间戳,以防需要表示定义良好的时间点。但是,如果您按照约定将时间点全部存储在UTC中,那么您还可以使用datetime获得时间点。


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

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

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

    这里有一些情况会让您后悔使用datetime,并希望您将数据存储在时间戳中。

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

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

  • 您接受来自世界各地不同客户机的数据,每个客户机都将时间插入其时区。
  • 简而言之

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

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

    这个答案仅仅是为了突出时间戳的灵活性和易用性,当涉及到时区时,它不包括任何其他的差异,如列大小、范围或分数。


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


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

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