1.4.5. 千年虫问题
MySQL本身是不存在千年虫问题的:
-
MySQL Server使用Unix时间函数把
2037
年以内的时间保存在TIMESTAMP
类型中。 使用DATE
和DATETIME
类型,则9999年以内的值都是可以接受的。 -
所有的MySQL的时间函数都在同一个源文件
sql/time.cc
里面实现,所有的代码都是是2000年安全的。 -
在MySQL,
YEAR
数据类型能够使用一个字节储存0年和
1901
到2155
年,并且使用四个数字显示。所有用两位数字表示的年份都被认为是1970
到2069
,比如你给一个类型为YEAR
的列插入数据01, MySQL Server 会认为它是2001。
下面简单的例子说明在MySQL Server中,使用DATE
或DATETIME
值表示9999年以内的时间, 和使用 TIMESTAMP
值表示2030年以前的时间,都是不会有任何问题的:
mysql>DROP TABLE IF EXISTS y2k;
Query OK, 0 rows affected (0.00 sec) mysql>CREATE TABLE y2k (date DATE,
->date_time DATETIME,
->time_stamp TIMESTAMP);
Query OK, 0 rows affected (0.01 sec) mysql>INSERT INTO y2k VALUES
->('1998-12-31','1998-12-31 23:59:59','1998-12-31 23:59:59'),
->('1999-01-01','1999-01-01 00:00:00','1999-01-01 00:00:00'),
->('1999-09-09','1999-09-09 23:59:59','1999-09-09 23:59:59'),
->('2000-01-01','2000-01-01 00:00:00','2000-01-01 00:00:00'),
->('2000-02-28','2000-02-28 00:00:00','2000-02-28 00:00:00'),
->('2000-02-29','2000-02-29 00:00:00','2000-02-29 00:00:00'),
->('2000-03-01','2000-03-01 00:00:00','2000-03-01 00:00:00'),
->('2000-12-31','2000-12-31 23:59:59','2000-12-31 23:59:59'),
->('2001-01-01','2001-01-01 00:00:00','2001-01-01 00:00:00'),
->('2004-12-31','2004-12-31 23:59:59','2004-12-31 23:59:59'),
->('2005-01-01','2005-01-01 00:00:00','2005-01-01 00:00:00'),
->('2030-01-01','2030-01-01 00:00:00','2030-01-01 00:00:00'),
->('2040-01-01','2040-01-01 00:00:00','2040-01-01 00:00:00'),
->('9999-12-31','9999-12-31 23:59:59','9999-12-31 23:59:59');
Query OK, 14 rows affected, 2 warnings (0.00 sec) Records: 14 Duplicates: 0 Warnings: 2 mysql>SELECT * FROM y2k;
+------------+---------------------+---------------------+ | date | date_time | time_stamp | +------------+---------------------+---------------------+ | 1998-12-31 | 1998-12-31 23:59:59 | 1998-12-31 23:59:59 | | 1999-01-01 | 1999-01-01 00:00:00 | 1999-01-01 00:00:00 | | 1999-09-09 | 1999-09-09 23:59:59 | 1999-09-09 23:59:59 | | 2000-01-01 | 2000-01-01 00:00:00 | 2000-01-01 00:00:00 | | 2000-02-28 | 2000-02-28 00:00:00 | 2000-02-28 00:00:00 | | 2000-02-29 | 2000-02-29 00:00:00 | 2000-02-29 00:00:00 | | 2000-03-01 | 2000-03-01 00:00:00 | 2000-03-01 00:00:00 | | 2000-12-31 | 2000-12-31 23:59:59 | 2000-12-31 23:59:59 | | 2001-01-01 | 2001-01-01 00:00:00 | 2001-01-01 00:00:00 | | 2004-12-31 | 2004-12-31 23:59:59 | 2004-12-31 23:59:59 | | 2005-01-01 | 2005-01-01 00:00:00 | 2005-01-01 00:00:00 | | 2030-01-01 | 2030-01-01 00:00:00 | 2030-01-01 00:00:00 | | 2040-01-01 | 2040-01-01 00:00:00 | 0000-00-00 00:00:00 | | 9999-12-31 | 9999-12-31 23:59:59 | 0000-00-00 00:00:00 | +------------+---------------------+---------------------+ 14 rows in set (0.00 sec)
最后两行中TIMESTAMP
列的值全部为0, 是因为我们添加的值(2040
, 9999
)超过了TIMESTAMP
的最大范围。TIMESTAMP
数据类型,是用来储存当前时间的,在32位的系统上只能表示'1970-01-01 00:00:00'
到 '2030-01-01 00:00:00'
的返回。在64位机器上,TIMESTAMP
可以处理2106
年以内的数据(无符号值)。
尽管MySQL Server本身是两千年安全的,你仍然可能会因为使用它的程序不是两千年安全的而遇到问题,比如,很多老程序使用两位数字储存和操作年份,而不是使用四位数字, This problem may be compounded by applications that use values such as 00
or 99
as “missing” value indicators. 很不幸,这种问题很难解决 因为不同的程序可能由不同的程序员编写,而他们可能使用不同的习惯和不同的时间处理函数。
因此, 即使 MySQL Server 没有千年虫问题,应用程序依然有责任提供明确的输入。 请查看 Section 11.3.4, “Y2K Issues and Date Types”, 以 了解MySQL Server对以两位数字表示时间的不明确的输入的处理规则。
相濡以沫,不如相忘于江湖