6

我一直在尝试将出生日期从我的 DB 转换为 DATE FORMat 但我面临的问题是 DOB 字段中有一些负值,当我从在线 FROM_UNIXTIME 计算器检查时,它会给出不同的结果,如果我检查它FROM_UNIXTIME(-957632400)然后对于负值,它总是返回 NULL。请让我知道如何从 -957632400 这样的 UNIX 格式中获取日期格式

4

2 回答 2

15

我们可以这样做:

FROM_UNIXTIME(0) + INTERVAL -957632400 SECOND

FROM_UNIXTIME函数受限于TIMESTAMP数据类型的允许范围,即标准的 32 位无符号整数范围 1970-01-01 到 2038-01-something。其他软件已更新为支持 64 位有符号整数,但 MySQL 尚未提供该功能(至少在 5.1.x 中没有)。

MySQL 中的解决方法是避免使用数据类型TIMESTAMP,而是使用DATETIME数据类型,当我们需要更大的范围时(例如 1970 年 1 月 1 日之前的日期)。

我们可以使用该DATE_ADD函数从 1970 年 1 月 1 日减去秒,如下所示:

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND)

注意在进行这些类型的计算时,您可能需要考虑 UTC 的时区“偏移量”。MySQL 会将 DATETIME 值解释为time_zone在当前 MySQL 会话的设置中指定,而不是 UTC ( time_zone = '+00:00')


跟进:

问:好的,意味着如果我们选择低于 '1970-01-01 00:00:00' 的日期,那么负值将保存在数据库中,否则它将是正值。正确的?– 软基因

答:呃,没有。如果选择 1970 年 1 月 1 日之前的日期/日期时间值,MySQL 将返回 1970 年 1 月 1 日之前的 DATE 或 DATETIME 值。如果存储 1970 年 1 月 1 日之前的 DATE 或 DATETIME 值,则 MySQL 将存储 1 月 1 日之前的 DATE 或 DATETIME 值, 1970,在这些数据类型支持的允许范围内。(类似于 0001-01-01 到 9999 ?)

如果您需要在数据库中存储非常大的正整数和负整数,您可能会将它们存储在定义为BIGINT.

DATE 列的内部表示需要 3 个字节的存储空间,而 DATETIME 需要 8 个字节的存储空间(直到 MySQL 版本 5.6.4。DATE 和 DATETIME 值的内部表示和存储在 5.6.4 中发生了变化)

所以不,MySQL 不会将 1970 年之前的日期值存储为“负整数”。

如果你想一想,MySQL 可以自由地实现他们想要的任何存储机制。(并且每个存储引擎都可以随意将该表示序列化到磁盘上。)

为什么一个日期需要 3 个字节?

MySQL 的一个选项(我并不表示这是它的完成方式)可能是将日期分解为它的年月日组件。

范围内整数值的表示 - 需要 -

  • 0 - 9999 -14 位

  • 0 - 12 - 4 位

  • 0 - 31 - 5 位

总共有 23 位,恰好适合 3 个字节。这只是表明 MySQL 没有必要将 1970 年 1 月 1 日之前的日期值表示为负整数,因此我们不应该假设它确实如此。(但如果我们正在为 MySQL 开发存储引擎,我们真的只关心这个级别的细节。)

于 2012-07-20T22:22:02.150 回答
1

从 DATETIME 到 unix 时间戳:

SELECT TIMESTAMPDIFF(SECOND, FROM_UNIXTIME(0), '1956-12-24 01:06:49');

从时间戳到 DATETIME:

SELECT DATE_ADD(convert_tz(FROM_UNIXTIME(0), @@session.time_zone,'+00:00'), INTERVAL -410914391 SECOND);

于 2017-12-26T16:26:59.750 回答