如何在数据库中存储非常旧的日期?

时间:2013-09-06 09:45:46

标签: mysql datetime

这实际上并不是我遇到的问题,但想象某人正在建立一个关于中世纪时期的网站,并希望存储日期,他们将如何处理它?<​​/ p>

MySQL的规范DATE表示它不会低于1000年。当格式为YYYY-MM-DD时,这是有道理的。如何在995中存储有关the death of Kenneth II of Scotland的信息?当然你可以把它存储为一个字符串,但是有真正的日期类型选项吗?

4 个答案:

答案 0 :(得分:4)

实际上,即使documentation澄清,你也可以在MySQL中存储1000年以下的日期:

mysql> describe test;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | YES  |     | NULL    |       |
| birth | date    | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+

- 您仍然需要以YYYY格式输入年份:

mysql> insert into test values (1, '0995-03-05');
Query OK, 1 row affected (0.02 sec)

mysql> select * from test;
+------+------------+
| id   | birth      |
+------+------------+
|    1 | 0995-03-05 |
+------+------------+
1 row in set (0.00 sec)

- 您将能够将其作为日期

进行操作
mysql> select birth + interval 5 day from test;                                                                              
+------------------------+                                                                                                   
| birth + interval 5 day |                                                                                                   
+------------------------+                                                                                                   
| 0995-03-10             |
+------------------------+
1 row in set (0.03 sec)

至于安全性。我从来没有遇到过这样的情况,这在MySQL 5.x中不起作用(原因,并不意味着它将100%起作用,但至少它在某种可能性下是可靠的)

关于BC日期(在基督之下)。我认为这很简单 - 在MySQL中,无法存储负面日期。即您需要将年份分别存储为有符号整数字段:

mysql> select '0001-05-04' - interval 1 year as above_bc, '0001-05-04' - interval 2 year as below_bc;
+------------+----------+
| above_bc   | below_bc |
+------------+----------+
| 0000-05-04 | NULL     |
+------------+----------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1441 | Datetime function: datetime field overflow |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

但我认为,无论如何(低于/高于0年),最好将日期部分存储为整数 - 这不会依赖于未记录的功能。但是,您需要使用这3个字段而不是日期(因此,在某种意义上,这不是您问题的解决方案)

答案 1 :(得分:2)

选择支持您要执行的操作的dbms。在其他免费数据库管理系统中,PostgreSQL支持从公元前4713年到公元294276年的时间戳。

如果将日期分解为年,月和日的单独列,则还需要更多表和约束来保证这些列中的值表示实际日期。如果这些列允许您存储值{2013,2,29},那么您的表就会被破坏。支持范围内日期的dbms完全避免了这种问题。

您可能遇到的其他问题

  • 超出范围的日期的日期算术运算不正确。
  • 超出范围的日期的特定于区域设置的格式设置不正确。
  • 日期和时间函数对超出范围的日期的惊人行为。
  • Gregorian calendar weirdness

格里高利历奇怪吗?在英国,1752年9月2日的第二天是1752年9月14日。PostgreSQL documents their rationale忽略了如下。

  

PostgreSQL使用Julian日期进行所有日期/时间计算。这有   正确计算从公元前4713年到远方的日期的有用特性   在未来,假设一年的长度是   365.2425天。

     

19世纪之前的日期惯例有趣的阅读,   但不足以保证编码到日期/时间   处理程序。

答案 2 :(得分:0)

可悲的是,我认为目前最简单的选择是将年,月和日存储在单独的字段中,年份为smallint

答案 3 :(得分:0)

引用http://dev.mysql.com/doc/refman/5.6/en/datetime.html

For the DATE and DATETIME range descriptions, “supported” means that although earlier values might work, there is no guarantee.

所以有一个很好的变化,如果配置足够的MySQL安装,更广泛的范围将起作用。

确保不使用TIMESTAMP,它似乎具有非负范围。

The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.

这是一个JavaScript示例,在UNIX纪元(1)之前,您可以使用2 ^ 36秒* -1000(达到Javascript的毫秒数)。

d = new Date((Math.pow(2, 36) - 1) * -1000)
Sun May 13 -208 18:27:45 GMT+0200 (Westeuropäische Sommerzeit)

所以我建议将历史日期存储为相对于纪元的BIGINT。

有关MxSQL 5.6的信息,请参阅http://dev.mysql.com/doc/refman/5.6/en/integer-types.html


(1)

epoch = new Date(0)
Thu Jan 01 1970 01:00:00 GMT+0100 (Westeuropäische Normalzeit)
epoch.toUTCString()
"Thu, 01 Jan 1970 00:00:00 GMT"