您建议使用datetime或timestamp字段吗?为什么(使用MySQL)?
我在服务器端使用PHP。
您建议使用datetime或timestamp字段吗?为什么(使用MySQL)?
我在服务器端使用PHP。
当前回答
在表上执行UPDATE语句时,请注意时间戳的更改。如果您有一个列为“Name”(varchar)、“Age”(int)和“Date_Add”(timestamp)的表,则运行以下DML语句
UPDATE table
SET age = 30
则“Date_Add”列中的每个值都将更改为当前时间戳。
其他回答
TIMESTAMP为4字节,DATETIME为8字节。
http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html
但正如斯克罗尼德所说,它的下限是1970年。不过,这对未来可能发生的任何事情都很好;)
也不DATETIME和TIMESTAMP类型在一般用例中基本上是断开的。MySQL将在未来改变它们。您应该使用BIGINT和UNIX时间戳,除非您有特定的理由使用其他时间戳。
特殊情况
以下是一些具体情况,在这些情况下,您的选择更容易,您不需要在这个答案中进行分析和提出一般建议。
仅限日期-如果您只关心日期(如下一个农历新年的日期,2022-02-01),并且您清楚了解该日期适用的时区(或不关心,如农历新年),则使用Date列类型。记录插入时间-如果您正在记录数据库中的行的插入日期/时间,并且您不担心应用程序在未来17年内会崩溃,那么继续使用默认值为CURRENT_TIMESTAMP()的TIMESTAMP。
为什么TIMESTAMP坏了?
TIMESTAMP类型以UTC时区存储在磁盘上。这意味着,如果您实际移动服务器,它不会损坏。很好✅. 但目前定义的时间戳将在2038年完全停止工作❌.
每次INSERT INTO或SELECT FROM TIMESTAMP列时,都会考虑客户端/应用程序服务器的物理位置(即时区配置)。如果移动应用程序服务器,则日期会中断❌.
(更新2022-04-29 MySQL在8.0.28中修复了这一问题,但如果您的生产环境位于CentOS 7或许多其他风格,那么您的迁移路径将需要很长时间才能获得此支持。)
为什么VARCHAR坏了?
VARCHAR类型允许以ISO8601格式明确地存储非本地日期/时间/两者,并且适用于2037年以后的日期。通常使用祖鲁时间,但ISO 8601允许对任何偏移进行编码。这不太有用,因为尽管MySQL日期和时间函数支持字符串作为输入,但如果输入使用时区偏移,则结果不正确。
VARCHAR还使用额外的存储字节。
为什么DATETIME中断?
DATETIME在同一列中存储DATE和TIME。除非时区被理解,并且时区没有存储在任何地方,否则这两个东西都没有任何意义❌. 您应该将预期的时区作为注释放在列中,因为时区与数据有着千丝万缕的联系。所以很少有人使用列注释,所以这是等待发生的错误。我从亚利桑那州继承了一台服务器,所以我总是需要将所有时间戳从亚利桑那州时间转换为另一个时间。
(更新2021-12-08我在多年的正常运行时间后重新启动了服务器,数据库客户端(带升级)重置为UTC。这意味着我的应用程序需要以不同的方式处理重置前后的日期。硬代码!)
DATETIME唯一正确的情况是完成以下句子:
您的2020年太阳新年正好从DATETIME(“2020-01-01 00:00:00”)开始。
DATETIMEs没有其他好的用途。也许你会想象一个特拉华州市政府的网络服务器。当然,这台服务器和所有访问这台服务器的人的时区都可以暗示在特拉华州,东部时区,对吧?错误的在这个千年里,我们都认为服务器存在于“云”中。因此,将您的服务器放在任何特定时区都是错误的,因为您的服务器总有一天会被移动。
注意:MySQL现在支持DATETIME文本中的时区偏移(谢谢@Marko)。这可能会使插入DATETIMEs更方便,但并不能解决数据的不完整和无用的含义,这一致命问题确定(“❌“)。
如何使用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))
);
插入默认值(thx Brad):
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分钟内购买的用户)超出了这里的范围。
我喜欢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);
时间戳和日期时间之间的另一个区别是时间戳,不能将默认值设置为NULL。
以下示例显示了在将时区更改为“america/new_york”(DATETIME不变)后,TIMESTAMP日期类型如何更改值。
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:日期时间与时间戳数据类型。