2009-09-06 9 views
8

SQLite docs especifica que el formato preferido para almacenar valores de fecha y hora en el DB es usar Julian Day (usando funciones incorporadas).¿Debo molestarme en almacenar los datos de DateTime como julianday en SQLite?

Sin embargo, todos los marcos que vi en python (pysqlite, SQLAlchemy) almacenan los valores datetime.datetime como cadenas con formato ISO. ¿Por qué lo están haciendo?

Normalmente estoy tratando de adaptar los marcos para almacenar datetime como julianday, y es bastante doloroso. Empecé a dudar de que valiera la pena el esfuerzo.

Por favor comparta su experiencia en este campo conmigo. ¿Seguir con julianday tiene sentido?

Respuesta

5

Almacénelo en ambos sentidos. Los marcos se pueden configurar de distintas maneras y si los suyos esperan encontrar una columna en bruto con una cadena con formato ISO, entonces probablemente sea más difícil moverse de lo que vale.

La preocupación en tener dos columnas es la consistencia de los datos, pero sqlite debe tener todo lo que necesita para que funcione. La versión 3.3 tiene soporte para restricciones de verificación y disparadores. Lea en date and time functions. Debería poder hacer completamente lo que necesita en la base de datos.

CREATE TABLE Table1 (jd, isotime); 

CREATE TRIGGER trigger_name_1 AFTER INSERT ON Table1 
BEGIN 
    UPDATE Table1 SET jd = julianday(isotime) WHERE rowid = last_insert_rowid(); 
END; 

CREATE TRIGGER trigger_name_2 AFTER UPDATE OF isotime ON Table1 
BEGIN 
    UPDATE Table1 SET jd = julianday(isotime) WHERE rowid = old.rowid; 
END; 

Y si usted no puede hacer lo que tiene dentro de la base de datos se puede escribir una extensión C para llevar a cabo la funcionalidad que necesita. De esta forma, no necesitará tocar el marco de trabajo aparte de cargar su extensión.

+0

¡Gracias por esta sugerencia! Es una gran idea y resuelve todos mis problemas con este problema. –

+1

¿Por qué querría _want_ almacenarlo en ambos sentidos? La única ventaja real de almacenar días julianos en cadenas con formato ISO es el espacio de almacenamiento. Si su marco espera una cadena con formato ISO, solo use eso. Todas las [funciones datetime] de SQLite (http://www.sqlite.org/lang_datefunc.html) puede procesar cadenas ISO igual de bien que los días julianos. – Martijn

6

Julian Day es útil para todo tipo de cálculos de fechas, pero puede almacenar el tiempo de parte decentemente (con horas precisas, minutos y segundos). En el pasado, he usado tanto los campos Julián Día (para fechas) como segundos-de-la-Época (para instancias datetime), pero solo cuando tenía necesidades específicas de cálculo (de fechas y, respectivamente, de veces). La simplicidad de las fechas y fechas de formato ISO, creo, debería hacer que sean la opción preferida, digamos aproximadamente el 97% de las veces.

+1

Así que me quedaré con los valores predeterminados del marco hasta que tenga razones explícitas para no hacerlo. Gracias! –

+0

¿Podría describir un poco acerca de por qué la precisión de julianday para horas, minutos y segundos no es lo suficientemente buena? –

+0

@Slava, piense en representar "1 segundo": ese 1/86400.'th de un día, que NO PUEDE representarse con precisión como la parte fraccionaria de un flotador de doble precisión porque la representación de este último es en forma binaria y 86400 no es una poder de dos. –

0

Porque 2010-06-22 00:45:56 es mucho más fácil de leer para un humano que 2455369.5318981484. Las fechas de texto son excelentes para realizar consultas ad-hoc en SQLiteSpy o SQLite Manager.

El principal inconveniente, por supuesto, es que las fechas de texto requieren 19 bytes en lugar de 8.

1

Pero por lo general, el ser humano no lee directamente de la base de datos. El tiempo fraccionario en un día juliano se puede convertir fácilmente a lectura humana por (por ejemplo)

void hour_time(GenericDate *ConvertObject) 
{ 
    double frac_time = ConvertObject->jd; 
    double hour   = (24.0*(frac_time - (int)frac_time)); 
    double minute  = 60.0*(hour - (int)hour); 
    double second  = 60.0*(minute - (int)minute); 
    double microsecond = 1000000.0*(second - (int)second); 

    ConvertObject->hour   = hour; 
    ConvertObject->minute  = minute; 
    ConvertObject->second  = second; 
    ConvertObject->microsecond = microsecond; 

}; 
Cuestiones relacionadas