16

这实际上不是我遇到的问题,但想象一下有人正在建立一个关于中世纪的网站并想要存储日期,他们会怎么做?

MySQL 的规范DATE说它不会低于 1000 年。当格式为YYYY-MM-DD. 您如何存储有关995 年苏格兰肯尼斯二世去世的信息?当然,您可以将其存储为字符串,但有真正的日期类型选项吗?

4

4 回答 4

4

实际上,您可以在 MySQL 中存储低于 1000 年的日期,尽管文档有说明:

mysql> 描述测试;
+-------+---------+------+------+---------+-------+
| 领域 | 类型 | 空 | 钥匙 | 默认 | 额外 |
+-------+---------+------+------+---------+-------+
| 编号 | 整数(11) | 是 | | 空 | |
| 出生| 日期 | 是 | | 空 | |
+-------+---------+------+------+---------+-------+

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

mysql> 插入测试值 (1, '0995-03-05');
查询正常,1 行受影响(0.02 秒)

mysql> 从测试中选择 *;
+--------+------------+
| 编号 | 出生|
+--------+------------+
| 1 | 0995-03-05 |
+--------+------------+
一组中的 1 行(0.00 秒)

-您将能够将此作为日期进行操作:

mysql>从测试中选择出生+间隔5天;                                                                              
+------------------------+                                                                                                   
| 出生+间隔5天|                                                                                                   
+------------------------+                                                                                                   
| 0995-03-10 |
+------------------------+
一组中的 1 行(0.03 秒)

至于安全。我从来没有遇到过这种情况在 MySQL 5.x 中不起作用(当然,这并不意味着它会 100% 起作用,但至少它在一定概率上是可靠的)

关于公元前日期(在基督之下)。我认为这很简单——在 MySQL 中也没有办法存储负日期。即您需要将年份单独存储为有符号整数字段:

mysql> select '0001-05-04' - 间隔 1 年 as above_bc,'0001-05-04' - 间隔 2 年 as below_bc;
+------------+----------+
| 以上_bc | 下面_bc |
+------------+----------+
| 0000-05-04 | 空 |
+------------+----------+
1 行,1 个警告(0.00 秒)

mysql> 显示警告;
+---------+------+-------------------------------- ------------+
| 水平 | 代码 | 留言 |
+---------+------+-------------------------------- ------------+
| 警告 | 第1441章 日期时间函数:日期时间字段溢出 |
+---------+------+-------------------------------- ------------+
一组中的 1 行(0.00 秒)

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

于 2013-09-06T09:55:30.567 回答
2

选择一个支持您想要做的事情的 dbms。在其他免费数据库管理系统中,PostgreSQL 支持从公元前 4713 年到公元 294276 年的时间戳范围。

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

您可能遇到的其他问题

  • 超出范围的日期的日期算术不正确。
  • 超出范围的日期的特定于区域设置的格式不正确。
  • 日期和时间函数在超出范围的日期上的令人惊讶的行为。
  • 公历怪事

公历怪异?在英国,1752 年 9 月 2 日之后的第二天是 1752 年 9 月 14 日。PostgreSQL 记录了他们忽略这一点的理由如下。

PostgreSQL 使用儒略日期进行所有日期/时间计算。这具有正确计算从公元前 4713 年到遥远未来的日期的有用属性,假设一年的长度为 365.2425 天。

19 世纪之前的日期约定读起来很有趣,但不够一致,不足以保证将其编码到日期/时间处理程序中。

于 2013-09-06T10:25:18.603 回答
0

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

于 2013-09-06T09:52:57.610 回答
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 示例,您可以在 2^36 秒 * -1000 之前获得 UNIX 纪元(1)多远(对于 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"
于 2013-09-06T10:33:29.160 回答