如果要声明包含小数秒部分的时态类型列,则需要把定义写成type_name(fsp),其中,type_name为TIME、DATETIME或TIMESTAMP,fsp为小数秒精度。例如,下面的TIME列允许 的小数位数分别为3位和6位:
t1 TIME(3) t2 TIME(6)
“零”值
- 当为某种日期/时间类型插入非法值时,该类型会把它存储为一个“零”值。
- 下图列出了各种日期/时 间类型的零值情况:
- 如果想要把非法值处理为错误,并拒绝接受,则需要设置相应的SQL模式,更多相关信息请 参考后面"处理无效值"相关文章 。
- “零”值也是那些声明时带有NOT NULL属性的日期/时间类型列的默认值。
INSERT INTO mytbl(date_col) VALUES(STR_TODATE('12-3-99','%m-%d-%Y')); SELECT * FROM mytbl;
类型转换
- 如果把DATE值赋值给DATETIME列,那么MySQL会自动把时间部分补足为'00:00:00'。反方向的转换也同样有效。
- 如果把DATETIME值赋值给DATE或TIME列,那么MySQL会把不相干的部分去掉。
- 例如:
CREATE TABLE t(dt DATETIME, d DATE, t TIME); INSERT INTO t(dt,d,t) VALUES(NOW(),NOW(),NOW()); SELECT * FROM t;
TIME到DATETIME的转换,依赖于具体的MySQL版本:自MySQL 5.6.4起,当前日期会添加上时间。对于以前的版本,这个转换并不一定会产生有意义的结果。
DATETIME和TIME的时间值区别
- 在MySQL里,DATATIME类型里的时间值与TIME值略有不同。
- 对于DATATIME类型,时间部分表示的是一天里的时间,且必须是在'23:59:59'的范围内。
- 但是,TIME值表示的则是一段逝去的时间。
- 这也正是文章开头图片里所示的TIME列的取值范围为何可以包含负值,以及为何可以大于’23:59:59'的具体原因。
取值范围
- TIMESTAMP类型列的取值范围是'1970-01-01 00:00:00[.000000]'~'2038-01-19 03:14:07[.999999]'。
- 与DATETIME一样,在MySQL 5.6.4之前,TIMESTAMP值也允许有小数秒部分,但在存储时会被丟弃。
- 它的取值范围与Unix时间密切相关,其中规定1970年的第一天为“零日”,也称作“纪元”。
- 对于每一个TIMESTAMP值,MySQL会用4个字节来把它存储为自纪元以来总共逝去的秒数。1970年的起始确定了TIMESTAMP类型的取值范围下限值。(不过请注意,TIMESTAMP的取值范围并非起始于'1970-01-0100:00:00'。你可能会想当然地认为它就是纪元以来的那个0秒,但0表示的时间戳是'0000-00-00 00:00:00')。取值范围上限值则与4个字节所能表示的最大Unix时间相对应。
时区
- MySQL会按世界标准时间(Universal Coordinated Time,UTC) 来存储TIMESTAMP值。
- 当保存这样 的值时,服务器会把它从会话时区转换为UTC。当以后检索该值时,服务器又会把它从UTC转换回会话时区,从而让你看到与你存储结果一样的时间值。
- 不过,如果另一个客户端使用了另一个时区去连接服务器,并检索该值,那么它所看到的值则是调整为其所设置时区的那个值 。
- 事实上,只要更改一下会话时区设置,就可以在一个会话里看到这样的效果。例如:
CREATE TABLE t(ts TIMESTAMP); SET time_zone = '+00:00' # 将时区设置为UTC INSERT INTO t VALUES('2000-01-01 00:00:00'); SELECT ts FROM t;
SET time_zone = '+03:00' # 将时区前调3个小时 SELECT ts FROM t;
在上面示例里,指定时区所采用的方式为:相对于UTC的小时和分钟的有符号偏移置。在后面"全球化问题"相关文章中我们还会介绍如何像类似于使用'Europe/Zurich'这样的时区名来更改时区设置。
YEAR(2)已被废弃
- YEAR(2)只显示最后两位数,并且这种类型实际只能存储从1970年到2069年之间的值。
- 如果使用YEAR(2)来存储该范围之外的值,那么最终的显示值将不确定。例如,YEAR(2)列里存储的1970和 2070都会显示为70。
- 避免这类问题的最简单方法是避免使用YEAR(2),用 YEA(4)来代替。
- 由于这样的存储问题,自MySQL 5.6.6起,就废弃了YEAR(2):在已有表里,YEAR(2)列会继续保持不变;但对于新表,这样的列会被创建为YEAR(4)。
NULL
- 时态列的定义可以包含通用属性NULL或NOT NULL。
- 如果都不指定,则默认为NULL。TIMESTAMP类型除外,其默认值为NOT NULL。
DEFAULT
- 也可以用DEFAULT子句来设定默认值。在另一篇文章中我们介绍了数据类型的默认值。
- 大部分情况下,这些默认值都必须为常量。
- 除了TIMESTAMP(自MySQL 5.6.5起)和DATETIME以外,你都不能使用像CURRENT_TIMESTAMP这样的函数来将DATETIME列的默认值设置为“当前日期和时间”。TIMESTAMP和DATETIME列之所以比较特殊,是因为它们的默认值可以为当前日期和时间。(更多与掌控这些类型默认值的规则相关的信息在下面"时态类型的自动特性"中会介绍)。如果其他类型想要得到这种结果,那么可以在每次创建新行时,显式地将该列的值设置为CURRENT_TIMESTAMP。 另外,也可以使用TIMESTAMP列或DATETIME列来代替,或者设置一个触发器,让它将该列初始化为适当的值(触发器参考https://dongshao.blog.csdn.net/article/details/90486999)。
- 在TIME、DATETIME和 TIMESTAMP类型的声明语法中,允许设置一个可选的小数秒精度(fsp),精度值最高可达6位数字。
- 值必须是0〜6,0表示没有小数部分,而6则表示精度为微秒。如果没有指定fsp,则默认值为0。
- 例如,TIME和TIME(0)是等价的,都没有小数部分。DATETIME(1)允许日期和时间值精确到十分之一秒。TIMESTAMP(6)允许时间戳的精确值达到微秒级。
SELECT CURTIME(), CURTIME(3);
语法格式
- 例如,下面是TIMESTAMP的语法格式(DATETIME也是一样的):
col_name TIMESTAMP [DEFAULT default_value] [ON UPDATE CURRENT_TIMESTAMP]
- 如果同时指定DEFAULT和ON UPDATE属性,它们的顺序无关紧要。
- DEFAULT默认值可以是:
- CURRENT_TIMESTAMP。
- 像0那样的常量值,或者是格式'CCYY-MM-DD hh:mm:ss'的值。
- 也可以使用CURRENT_TIMESTAMP的同义词,如NOW()。
- 自MySQL 5.6.5起,DATETIME列便开始允许这些与DEFAULT和ON UPDATE一样的属性。在5.6.5版本之前,对于DEFAULT属性,DATETIME只允许常量,并且不支持ON UPDATE。
- 如果想让表里的第一个TIMESTAMP列具有一个或两个自动特性,那么可以组合使用DEFAULT属性和ON UPDATE属性来定义它:
- 如果使用DEFAULT CURRENT_TIMESTAMP,那么列将拥有自动初始化特性。如果指定ON UPDATE CURRENTJTIMESTAMP,那么它还会拥有自动更新特性。
- 如果两种属性都没有指定,那么MySQL会将列定义为具有DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP两种属性。
- 如果使用指定了常量值的DEFAULT constant_value属性,那么列将不具有自动初始化特性。如果指定ON UPDATE CURRENT_TIMESTAMP,那么它会有自动更新特性。
- 如果没有DEFAULT,但有ON UPDATE CURRENT_TIMESTAMP,那么具体的默认 值为0,并且列有自动更新特性。
NULL
- TIMESTAMP和DATETIME列的定义也可以包含NULL或NOT NULL属性。
- TIMESTAMP的默认属性是NOT NULL。
- 这会产生一种特殊效果,即当你把列显式地设置成NULL时,MySQL会将它设置成当前时间戳。(对于插入和更新操作,都是如此)。
- 如果在列的定义里指定NULL,那么将该列设置为NULL时,存储的将是NULL,而不是当前时间戳。
- DATETIME的默认属性是NULL,并且在把DATETIME列设置为NULL时,没有产生特殊效果。
演示案例
- 有如下一张表,包含TIMESTAMP列。在新增行时,列会被设置成当前时间戳,并且之后不会 被自动更新:
CREATE TABLE t1(ts_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
- 如果要插入新行,可以通过如下几种方式将新行中的ts_create字段设置为当前时间戳:
- 将列设置为NULL
- 在INSERT语句中省略ts_create字段
- 下面来看另外一张表:其中包含两个TIMESTAMP类型的列,这两个列分别用于存储创建时间和最周修改时间。
CREATE TABLE t2( ts_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ts_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); INSERT INTO t2;
- 插入一行进行测试:
INSERT INTO t2 VALUES(); SELECT * FROM t2;
'CCYY-MM-DD hh:mm:ss[.uuuuuu[' 'YY-MM-DD hh:mm:ss[.uuuuuu]' 'CCYYMMDDhhmmss[.uuuuuu]' 'YYMMDDhhmmss[.uuuuuu]' CCYYMMDDhhmmss[.uuuuuu] YYMMDDhhmmss[.uuuuuu]
分隔符处理
- 对于带分隔符的字符串格式,日期里可以不用"-",时间里可以不用":"。
- 任何一种标点符号都可以用作分隔符。对这些值的解释,依据的是其上下文,而非分隔符。例如,虽然人们习惯于把“:”当作时间值的分隔符,但是在期望是日期值的场合,MySQL也不会把一个包含“:”的值解释为具体的时间。
- 此外,对于包含有分隔符的字符串格式,当月、日、时,分或秒的值小于10时,可以不用指定2位数字。例如,下面这些值都是等价的。
'2012-02-03 05:04:09' '2012-02-03 05:04:9' '2012-02-03 05:4:9' '2012-02-03 5:4:9' '2012-02-3 5:4:9' '2012-2-3 5:4:9'
前导零
- 对于带有前导零的日期和时间值,MySQL有多种不同的解释方式,具体取决于这些值是以字符串形式指定的,还是以数字形式指定的。
- 例如,字符串'001231'会被看作是一个有6位数字的值:
- 如果将其当作DATE类型,那么它会被解释成'2000-12-31'。
- 而如果将其当作DATETIME类型,那么它会被解释成'2000-12-31 00:00:00'。
- 另外,在解析器将其处理成数字之后,数字001231会被看作1231,于是,对它的解释就会变得不确定。此时,最好是提供一个字符串值'001231'。
- 如果的确需要使用数字,则需要使用完整形式(对于DATE类型,即为20001231;而对于DATETIME类型,即为200012310000)。
CREATE TABLE y_table (y YEAR(4)); INSERT INTO y_table VALUES(68),(69),(99),(00),('00'); SELECT * FROM y_table;
演示案例
- 查询2005年9月的所有订单
- 当然,我们还可以进行简化
演示案例
- 我们有下面这个查询语句。如果order_date的类型是datetime类型(例如:2005-09-01 11:30:05),那么order_date中还会包含时分秒,下面的查询就会失败
- 因此,我们可以借助date()函数来解决上面那种错误
- 因此,如果查询要的是日期,那么就建议使用date()函数
- 类似的,time()函数等原理都如同上面