不是很好的标题,所以我道歉。
出于某种原因,(我不是那个人,我离题了)我们有一个表结构,其中日期的字段类型是varchar。 (奇)。
我们有一些日期,例如:
1932-04-01 00:00:00 and 1929-07-04 00:00:00
我需要做一个查询,将这些日期字符串转换为unix时间戳,但是,如果你转换1970年以前的日期,它将返回0。
有任何想法吗?
非常感谢!
编辑:错误的日期格式。哎呀。
啊哈!我们找到了解决方案!
要做的SQL:
SELECT DATEDIFF( STR_TO_DATE('04-07-1988','%d-%m-%Y'),FROM_UNIXTIME(0))*24*3600 -> 583977600
SELECT DATEDIFF( STR_TO_DATE('04-07-1968','%d-%m-%Y'),FROM_UNIXTIME(0))*24*3600 -> -47174400
这可能有助于将来参考。
我已经改编了DATEDIFF工作方式,也包括时间而不仅仅是几天。我已将其包装到存储函数中,但如果您不想使用函数,则可以将SELECT部分解压缩。
DELIMITER |
CREATE FUNCTION SIGNED_UNIX_TIMESTAMP (d DATETIME)
RETURNS BIGINT
DETERMINISTIC
BEGIN
DECLARE tz VARCHAR(100);
DECLARE ts BIGINT;
SET tz = @@time_zone;
SET time_zone = '+00:00';
SELECT DATEDIFF(d, FROM_UNIXTIME(0)) * 86400 +
TIME_TO_SEC(
TIMEDIFF(
d,
DATE_ADD(MAKEDATE(YEAR(d), DAYOFYEAR(d)), INTERVAL 0 HOUR)
)
) INTO ts;
SET time_zone = tz;
return ts;
END|
DELIMITER ;
-- SELECT UNIX_TIMESTAMP('1900-01-02 03:45:00');
-- will return 0
-- SELECT SIGNED_UNIX_TIMESTAMP('1900-01-02 03:45:00');
-- will return -2208888900
将这些日期字符串转换为unix时间戳
传统的Unix时间戳是自1970年1月1日以来的无符号整数计数秒,因此不能代表之前的任何日期。
根据您用于表示时间戳的系统,您最多会得到混合结果。
关于Unix time_t是应该签名还是未签名,最初存在一些争议。如果未签名,其未来的范围将加倍,推迟32位溢出(68年)。然而,它将无法代表1970年之前的时间。当被问及这个问题时,Dennis Ritchie说他没有深入思考这个问题,但他认为能够代表他一生中的所有时间。会好的。 (Ritchie的诞生,在1941年,大约是Unix时间-893 400 000.)共识是time_t签署,这是通常的做法。 QNX操作系统版本6的软件开发平台具有无符号的32位time_t,但旧版本使用了签名类型。
似乎MySQL将时间戳视为无符号整数,这意味着Epoc之前的时间将全部解析为0。
在这种情况下,您始终可以选择实现自己的无符号时间戳类型,并将其用于计算。
如果它对您的问题可行,您可以将所有mysql时间换算,比如说100年,然后使用这些调整后的时间戳或重新计算负时间戳值。
正如一些人所说,确保你的系统使用64位代表时间戳,否则你将遇到2038年的问题。
我没有尝试过上面的解决方案,但如果您无法以时间戳的形式从MySQL数据库中检索日期值,那么也可以尝试此操作
SELECT TIMESTAMPDIFF(第二,FROM_UNIXTIME(0),'1960-01-01 00:00:00');
获得最大值范围+/-明智地在您的生日区域使用此查询,在我的情况下“yyyy-mm-dd”但您可以根据需要更改它
select name, (@bday:=STR_TO_DATE(birthday,"%Y-%m-%d")),if(year(@bday)<1970,UNIX_TIMESTAMP(adddate(@bday, interval 68 year))-2145916800,UNIX_TIMESTAMP(@bday)) from people
使用日期而不是时间戳。日期将解决您的问题。检查这个link