MySQL 日期时间存储类型 datetime、timestamp 以及 int 的联系和区别
大概印象
这三个类型都可以用来存储日期时间,datetime
和 timestamp
展现形式如 '2020-07-27 14:25:30'
,int 则是整型存储秒数,形如 1595852730
。
个人通常会用 int 类型存储日期时间,一开始是觉得比较方便,因为 time()
获取当前的(与 1970-01-01 08:00:00
间隔的)秒数可以直接存入数据库。显示的时候秒数方便通过 date()
转化其他任意想要的日期时间格式。且日期时间以整型存储在排序的时候整型更直观。
但这其实都是我自己的想法,datetime
和 timestamp
在 PHP 存入数据库的时候,可以设置明确的(字符串类型)值,也可以借助 MySQL 自带的字段属性便捷设置。如果是显示默认格式的日期时间,datetime
和 timestamp
倒是比较方便的;但如果需要显示特定格式的日期,比如说几分钟,几小时这种形式(借助自定义的公共函数实现),需要先转化为 int
类型秒数,再转化为想要的日期时间格式。此外,datetime
和 timestamp
是可以正常比较大小进行排序的。如果是在查询条件中需要指定日期或者时间,可以通过 MySQL 的 SUBSTR(addtime FROM 1 FOR 10)
方法截取比较部分(与 PHP 中的库函数相比,MySQL 中的 SUBSTR()
默认的开始值是 1,而非 0,这点需要注意的)。这一点上,比 int 类型通过比较范围(例子在下面)或者通过 sql 时间戳和日期格式转换 之后再用 SUBSTR()
方法截取进行比较方便得多。
-- int 类型存储日期时间,筛选 2020-07-27 的记录
`time` >= UNIX_TIMESTAMP('2020-07-27 00:00:00') AND `time` <= UNIX_TIMESTAMP('2020-07-27 23:59:59')
datetime、timestamp 以及 int 的联系和区别
联系就是都能存储时间日期了,主要看区别。
自动更新日期
原文 mysql 的 datetime 和 timestamp 的区别还挺多,需要注意细节 在这一点上我是不完全认同的。
原文说 datetime
默认值为 null
不会自动更新,而 timestamp
默认值为 not null
的时候,默认时间和之后的更新时间都为当前时间 CURRENT_TIMESTAMP
。这其实是不对的,默认值都不一样,哪有什么可比性。而且默认时间和更新时间只与当前设置的默认值和更新值有关的。
我的测试环境:MySQL 5.6
,Navicat 11.1.13
。
两个类型的默认值都可以自定义,当设置为 CURRENT_TIMESTAMP
(DEFAULT CURRENT_TIMESTAMP
),插入记录时字段值自动保存为当前时间。当设置为空时,datetime 为空,timestamp 为 0000-00-00 00:00:00
。但插入记录时,都显示 0000-00-00 00:00:00
。而当设置为 null 时,两者默认值也都会 null,插入记录也为 null。
自动更新日期主要使用到是另外一个字段属性 ON UPDATE
。ON UPDATE CURRENT_TIMESTAMP
约定更新记录时更新当前字段值为当前时间(更新时间)。这个属性在当前测试环境的 Navicat 设计表界面,timestamp 有一个 根据当前时间戳更新
的 checkbox 选项,会自动默认勾选,而 datetime 没有。这就让原文作者有一个错觉,timestamp 类型会自动更新,而 datetime 不会。其实归根结底,还是 ON UPDATE
在起作用。测试发现,datetime 虽然没有这个自动更新的选择项,但可以通过更改数据库表结构语句进行修改设置。具体操作如下:
ALTER TABLE `xxx`
MODIFY COLUMN `ddatetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
当 datetime 和 timestamp 两个类型的字段设置默认值为 null 后,属性值勾选 not null 进行保存更新(Navicat),timestamp 会自动设置默认值为 CURRENT_TIMESTAMP,并自动勾选 根据当前时间戳更新
;而 datetime 默认值为空。
int 默认值为 0,就是 1970-01-01 00:00:00
(服务器上 php -r "echo date('Y-m-d H:i:s',0);"
的测试结果,本地 Windows 测试为 1970-01-01 01:00:00
,不清楚什么原因导致的)。
日期存储方式
timestamp 存储的时间会自动转换为 utc (格林威治标准时间),北京时间是东八区和它差了 8 个小时,在存储的时候会减去 8 小时,所以如果你是用 mybatis 操作的读取,需要配置下再加上 8 小时(Java 还没自学到哪一块,尴尬)
datetime 不需要做出任何转变,与时区无关。这点在跨时区迁移数据时可能会造成影响。
int 不清楚...猜测跟 timestamp 一致,即与时区有关。
支持范围不一样
timestamp 支持的范围是 1970-01-01 00:00:01
到 2038-01-19 03:14:07
,在数据库用整型的 int 型存储,int 型的范围是 2 的 32 次方减 1。
datetime 支持的日期范围是 从 0000-00-00 00:00:00
到 9999-12-31 23:59:59
。
int 与 timestamp 支持范围一致。
使用 timestamp 可能出现的错误
如果用 timestamp 存储数据,最早时间是 “1970-01-01 00:00:01”,可是在存入数据库的时候,因为数据库会自动减去 8 小时,这样一来,时间就变成 1969 年了,你会发现报错误了,可是这个异常又不是经常发生。
在设置自定义的 timestamp 的时候,使用 1970-01-01 08:00:00
或者小于这个的日期时间插入时,会自动保存成 '0000-00-00 00:00:00'
,而 1970-01-01 08:00:01
和大于这个的日期时间插入,显示正常。与其默认值设置无关,与当前时区有关。暂未发现错误或错误提示,猜测原文作者遇到的错误,可能是因为 Java 语言的报错,或者不同类型的数据库产生的错误。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
Hello,
Wondering if you accepted guest posts on your site. Also would you be willing to insert links in existing posts?
How much would you charge for this?
Justin
Sorry, i can't accept inserting links in my posts.
And my posts are chinese, i don't think they are useful or helpful for you.