2010-05-07 13 views
13

No es un título muy bueno, así que mis disculpas.Convertir una cadena de fecha que está antes de 1970 en una marca de tiempo en MySQL

Por alguna razón, (yo no era la persona que lo hizo, yo estoy divagando) tenemos una estructura de tabla donde el tipo de campo para una fecha es varchar. (impar).

Tenemos algunas fechas, tales como:

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

Necesito hacer una consulta que convertirá estas cadenas de fecha en una marca de tiempo Unix, sin embargo, en MySQL si convierte una fecha que es anterior a 1970 devolverá 0.

¿Alguna idea?

¡Muchas gracias!

EDITAR: Formato de fecha incorrecta. ooops.

+0

Además, si convierto una fecha anterior a 1970 en una marca de tiempo, esperaría un valor negativo. – Flukey

+0

¿Por qué una marca de tiempo de Unix? Me gustaría invertir algo de tiempo en averiguar si puede usar algo más que marcas de tiempo de Unix, como tratar con marcas de tiempo de Unix <1970 en una gran lata de gusanos ... – nos

+0

@nos - Estoy de acuerdo con usted por completo, sin embargo, ay, no es mi trabajo para hacer eso. Es una de esas cosas en las que un colega vino corriendo a preguntarme si podía ayudarlo con un problema. He recomendado cambiarlo, pero todo depende de él. – Flukey

Respuesta

17

Aha! ¡Hemos encontrado una solución!

El SQL para hacerlo:

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 

Esto podría ser útil para futuras referencias.

Puedes probarlo aquí: http://www.onlineconversion.com/unix_time.htm

+0

¿Es esto independiente del servidor t? imezone? – Neil

+0

ver mi versión a continuación – TheBelgarion

2

convertir estas cadenas de fecha en un sello de tiempo Unix

marcas de tiempo tradicional de Unix son un recuento entero sin signo de segundos desde el 1-Ene-1970, por lo tanto no puede representar cualquier fecha antes de eso.

+1

Puede si devuelve un valor negativo. PHP, por ejemplo, puede comprender un valor de marca de tiempo negativo y convertir a una cadena ... – Flukey

2

En el mejor de los casos tendrá resultados mixtos dependiendo del sistema que esté utilizando para representar la marca de tiempo.

De wikipedia

originalmente había una cierta controversia sobre si el time_t UNIX deben ser con o sin signo. Si no se firma, su rango en el futuro sería duplicado, posponiendo el desbordamiento de 32 bits (en 68 años). Sin embargo, entonces sería incapaz de tiempos que representan antes de 1970. Dennis Ritchie, cuando se le preguntó acerca de este tema , dijo que no había pensado muy profundamente sobre ello, pero era de la opinión de que la capacidad de representar todas las veces en su vida sería agradable. (El nacimiento de Ritchie, en 1941, es alrededor del tiempo Unix -893 400 000.) El consenso es para time_t para firmar, y esta es la práctica habitual. La plataforma de desarrollo de software para versión 6 del sistema operativo QNX tiene un time_t sin firmar de 32 bits, aunque las versiones anteriores de utilizan un tipo firmado.

Parece que las marcas de tiempo MySQL trata como un entero sin signo, lo que significa que los tiempos antes de la Epoc serán todos resolver a 0.

Siendo este el caso, siempre tiene la opción de implementar su propio tipo de marca de tiempo sin firmar y usa eso para tus cálculos.

2

Si es factible para su problema, puede cambiar todos sus tiempos de mysql en, digamos 100 años, y luego trabajar con esas marcas de tiempo ajustadas o volver a calcular el valor de marca de tiempo negativo.

Como han dicho algunos, asegúrese de que su sistema esté usando 64bits para representar la marca de tiempo, de lo contrario, llegará al problema del año 2038.

+0

Acabo de leer eso y pensé: ¡qué maldita idea! : D y luego nos damos cuenta de que estamos ejecutando un sistema de 32 bits. :-( Estaba haciendo un poco de Google y aparentemente puedo usar date_add para obtener el intervalo de segundos entre 1970 y una fecha de nacimiento y luego menos el intervalo de 1970. Espero que tenga sentido. Por ejemplo, yo tener esto en este momento: SELECCIONAR date_add ('1970-01-01', intervalo t.testdate second) como testdate_timestamp FROM random.test t; Pero, ¡ay !, eso es todo lo que tengo! – Flukey

+0

Don No confundas el 64bit con el hardware. Tal vez tu sistema pueda manejarlo, pruébalo. Además, dependiendo de tus necesidades, podrías usar la base de datos para hacer toda tu lógica relacionada con la fecha para que no tengas que preocuparte por ello. en PHP, por ejemplo, en PHP podría simplemente trabajar con, digamos, años. – zaf

-2

Fecha de uso en lugar de marcas de tiempo. La fecha resolverá tus problemas. verifique esto link

4

He adaptado la solución DATEDIFF para incluir también el tiempo no solo días. Lo envolví en una función almacenada, pero puedes extraer la parte SELECCIONAR si no quieres usar funciones.

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 
0

Para obtener el max. Rango +/- uso racional esta consulta en el campo de cumpleaños, en mi caso "aaaa-mm-dd", pero se puede cambiar a sus necesidades

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 
0

no he probado las soluciones anteriores, pero esto podría, en caso no puede recuperar el valor de la fecha de la base de datos MySQL en forma de marca de tiempo, entonces esta operación también se puede probar

SELECCIONAR TIMESTAMPDIFF (segundo, FROM_UNIXTIME (0), '1960-01-01 00:00: 00 ');

Cuestiones relacionadas