将1970年之前的日期字符串转换为MySQL中的时间戳

时间:2010-05-07 12:42:28

标签: mysql

不是很好的头衔,所以我道歉。

出于某种原因,(我不是那个人,我离题了)我们有一个表结构,其中日期的字段类型是varchar。 (奇数)。

我们有一些日期,例如:

1932-04-01 00:00:00 and 1929-07-04 00:00:00

我需要进行一个查询,将这些日期字符串转换为unix时间戳,但是,如果你转换1970年之前的日期,它会返回0。

有什么想法吗?

非常感谢!

编辑:错误的日期格式。哎呀。

9 个答案:

答案 0 :(得分:17)

啊哈!我们找到了解决方案!

执行此操作的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 

这可能对将来参考有用。

您可以在此处进行测试:http://www.onlineconversion.com/unix_time.htm

答案 1 :(得分:4)

我已经改编了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

答案 2 :(得分:2)

  

将这些日期字符串转换为   unix时间戳

传统的Unix时间戳是自1970年1月1日以来的无符号整数计数,因此无法表示此之前的任何日期。

答案 3 :(得分:2)

根据您用来表示时间戳的系统,您最多会得到混合结果。

来自wikipedia

  

最初存在一些争议   关于Unix time_t是否应该   签名或未签名。如果未签名,   它的未来范围将是   加倍,推迟32位   溢出(68年)。但是,它   然后将无能为力   代表1970年以前的时间。   当被问及此事时,丹尼斯里奇   问题,说他没有想到   非常深刻的,但它是   认为能够代表的能力   在他一生中的所有时间都是   不错。 (里奇的出生,在1941年,是   在Unix时间-893 400 000.)   达成共识是为了签署时间表,   这是通常的做法。该   软件开发平台   QNX操作系统的第6版   但是有一个无符号的32位time_t   旧版本使用签名类型。

似乎MySQL将时间戳视为无符号整数,这意味着Epoc之前的时间都将解析为0。

在这种情况下,您始终可以选择实现自己的无符号时间戳类型,并将其用于计算。

答案 4 :(得分:2)

如果它可以解决您的问题,您可以将所有mysql时间换算,比如100年,然后使用这些调整后的时间戳或重新计算负时间戳值。

正如一些人所说,确保你的系统使用64位代表时间戳,否则你将遇到2038年的问题。

答案 5 :(得分:1)

我没有尝试过上述解决方案,但如果您无法以时间戳的形式从MySQL数据库中检索日期值,那么也可以尝试此操作

SELECT TIMESTAMPDIFF(second,FROM_UNIXTIME(0),'1960-01-01 00:00:00');

答案 6 :(得分:0)

获得最大值范围+/-明智地在您的生日字段上使用此查询,在我的情况下" 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

答案 7 :(得分:0)

我觉得我们让这件事变得太困难了...

使用下面的函数,您可以将任何内容与 unix 时间戳相互转换,就像在浏览器中所做的一样。

像这样调用函数:

select to_unix_time('1776-07-04 10:02:00'),
from_unix_time(-6106024680000);

通过编译这些:

delimiter $$
create function to_unix_time (
    p_datetime datetime
) returns bigint
deterministic
begin
    declare v_ret bigint;
    
    select round(timestampdiff(
        microsecond,
        '1970-01-01 00:00:00',
        p_datetime
    ) / 1000, 0)
    into v_ret;
    
    return v_ret;
end$$

create function from_unix_time (
    p_time bigint
) returns datetime(6)
deterministic
begin
    declare v_ret datetime(6);
    
    select '1970-01-01 00:00:00' +
    interval (p_time * 1000) microsecond
    into v_ret;
    
    return v_ret;
end$$

答案 8 :(得分:-2)

使用日期而不是时间戳。日期将解决您的问题。 检查此link