【IT168 技术】MySQL数据库中有五种与日期和时间有关的数据类型,各种日期数据类型所占空间如表2-1所示。
DATETIME和 DATE
DATETIME占用8字节,是占用空间最多的一种日期类型。它既显示了日期,同时也显示了时间。其可以表达的日期范围为“1000-01-01 00:00:00”到“9999-12-31 23:59:59”。
DATE占用3字节,可显示的日期范围为“1000-01-01”到“9999-12-31”。
在MySQL数据库中,对日期和时间输入格式的要求是非常宽松的,以下的输入都可以视为日期类型。
·2011-01-01 00:01:10
·2011/01/01 00+01+10
·20110101000110
·11/01/01 00@01@10
其中,最后一种类型中的“11”有些模棱两可,MySQL数据库将其视为2011还是1911呢?下面来做个测试:
*************************** 1. row ***************************
datetime: 2011-01-01 00:01:10
1 row in set (0.00 sec)
可以看到数据库将其视为离现在最近的一个年份,这可能不是一个非常好的习惯。如果没有特别的条件和要求,还是在输入时按照标准的“YYYY-MM-DD HH:MM:SS”格式来进行。在MySQL 5.5版本之前(包括5.5版本),数据库的日期类型不能精确到微秒级别,任何的微秒数值都会被数据库截断,例如:
Query OK, 0 rows affected (0.25 sec)
mysql> INSERT INTO t SELECT '2011-01-01 00:01:10.123456';
Query OK, 1 row affected (0.05 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2011-01-01 00:01:10
1 row in set (0.00 sec)
不过MySQL数据库提供了函数MICROSECOND来提取日期中的微秒值,示例如下:
*************************** 1. row ***************************
MICROSECOND('2011-01-01 00:01:10.123456'): 123456
1 row in set (0.00 sec)
有意思的是, MySQL的CAST函数在强制转换到DATETIME时会保留到微秒数,不过在插入后同样会截断,示例如下:
*************************** 1. row ***************************
D: 2011-02-01 00:01:10.123456
1 row in set (0.00 sec)
mysql> INSERT INTO t
->SELECT CAST('2011-02-01 00:01:10.123456' AS DATETIME);
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2011-01-01 00:01:10
*************************** 2. row ***************************
a: 2011-02-01 00:01:10
2 rows in set (0.00 sec)
然而从MySQL 5.6.4版本开始,MySQL增加了对秒的小数部分(fractional second)的支持,具体语法为:
其中,type_name的类型可以是TIME、DATETIME和TIMESTAMP。fsp表示支持秒的小数部分的精度,最大为6,表示微秒(microseconds);默认为0,表示没有小数部分,同时也是为了兼容之前版本中的TIME、DATETIME和TIMESTAMP类型。对于时间函数,如CURTIME()、SYSDATE()和UTC_TIMESTAMP()也增加了对fsp的支持,例如:
*************************** 1. row ***************************
TIME: 10:22:37.4456
1 rows in set (0.00 sec)
注意 MariaDB 5.3版本就对TIME、DATETIME、TIMESTAMP类型的微秒部分进行了支持。详细的说明可以从http://kb.askmonty.org/en/microseconds-in-mariadb中得到。
${PageNumber}TIMESTAMP
TIMESTAMP和DATETIME显示的结果是一样的,都是固定的“YYYY-MM-DD HH:MM:SS”的形式。不同的是,TIMESTAMP占用4字节,显示的范围为“1970-01-01 00:00:00”UTC到“2038-01-19 03:14:07”UTC。其实际存储的内容为“1970-01-01 00:00:00”到当前时间的毫秒数。
注意 UTC 协调世界时,又称世界统一时间、世界标准时间和国际协调时间。它从英文Coordinated Universal Time和法文Temps Universel Cordonné而来。
TIMESTAMP类型和DATETIME类型除了在显示时间范围上有所不同外,还有以下不同:
在建表时,列为TIMESTAMP的日期类型可以设置一个默认值,而DATETIME不行。
在更新表时,可以设置TIMESTAMP类型的列自动更新时间为当前时间。
首先来看一个默认设置时间的例子。
-> ( a INT,
-> b TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-> )ENGINE=InnoDB;
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t (a) VALUES (1);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 1
b: 2011-02-02 16:42:57
1 row in set (0.01 sec)
接着来看一个执行UPDATE时更新为当前时间的例子。
-> ( a INT ,
-> b TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-> );
mysql> INSERT INTO t SELECT 1,CURRENT_TIMESTAMP;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 1
b: 2011-02-02 16:45:40
1 row in set (0.01 sec)
# 等待一段时间
mysql> UPDATE t SET a=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
可以发现在执行UPDATE操作后,b列的时间由原来的16:45:40更新为了16:47:39。如果执行了UPDATE操作,而实际上行并没有得到更新,那么是不会更新b列的,例如:
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
mysql> UPDATE t SET a=2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> SELECT * FROM t\G;
*************************** 1. row ***************************
a: 2
b: 2011-02-02 16:47:39
1 row in set (0.00 sec)
可以看到执行UPDATE t SET a=2并没有改变行中的任何数据,显示Changed:0表示该行实际没有得到更新,故b列并不会进行相应的更新操作。
当然,可以在建表时将TIMESTAMP列设为一个默认值,也可以设为在更新时的时间,例如:
-> a INT,
-> b TIMESTAMP DEFAULT ON UPDATE CURRENT_TIMESTAMP
->)ENGINE=InnoDB;
YEAR和TIME
YEAR类型占用1字节,并且在定义时可以指定显示的宽度为YEAR(4)或YEAR(2),例如:
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO t SELECT '1990';
mysql> SELECT * FROM t;
+------+
| a |
+------+
| 90 |
+------+
1 row in set (0.00 sec)
对于YEAR(4),其显示年份的范围为1901~2155;对于YEAR(2),其显示年份的范围为1970~2070。在YEAR(2)的设置下,00~69代表2000~2069年。
TIME类型占用3字节,显示的范围为“-838:59:59”~“838:59:59”。有人会奇怪为什么TIME类型的时间可以大于23。因为TIME类型不仅可以用来保存一天中的时间,也可以用来保存时间间隔,同时这也解释了为什么TIME类型也可以存在负值。和DATETIME类型一样,TIME类型同样可以显示微秒时间,但是在插入时,数据库同样会进行截断操作,例如:
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO t SELECT '14:40:20.123456';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM t;
+----------+
| a |
+----------+
| 14:40:20 |
+----------+
1 row in set (0.00 sec)