2010-11-25 91 views
12

Tengo problemas de diseño con el almacenamiento/recuperación de datos usando Python y SQLite.Almacenamiento y conversión de fecha SQLite

Entiendo que una columna de fecha SQLite almacena las fechas como texto en formato ISO (es decir, '2010-05-25'). Así que cuando puedo mostrar una fecha británica (por ejemplo. En una página web) que convertir la fecha usando

datetime.datetime.strptime(mydate,'%Y-%m-%d').strftime('%d/%m/%Y') 

Sin embargo, cuando se trata de datos de escritura de nuevo a la mesa, SQLite es muy perdona y es muy feliz '25/06/2003' para almacenar en un campo de fecha, pero esto no es lo ideal porque

  • me podía quedar con una mezcla de formatos de fecha en la misma columna de ,

  • Las funciones de fecha de SQLite solo funcionan con formato ISO.

por lo tanto necesito para convertir la cadena de fecha de nuevo a formato ISO antes cometer, pero entonces se necesitaría una función genérica que comprueba los datos a punto de escribirse en todos los campos de fecha y convierte a la norma ISO si es necesario. Eso suena un un poco tedioso para mí, pero tal vez sea inevitable.

¿Hay soluciones más simples? ¿Sería más fácil cambiar el campo de fecha a un campo de 10 caracteres y almacenar 'dd/mm/yyyy' en toda la tabla? De esta forma, no es necesaria ninguna conversión de al leer o escribir desde la tabla, y podría usar las funciones de datetime() si tuviera que realizar cualquier aritmética de fecha.

¿Cómo han superado este problema otros desarrolladores? Cualquier ayuda sería apreciada. Para el registro, estoy usando SQLite3 con Python 3.1.

Respuesta

14

Si establece detect_types=sqlite3.PARSE_DECLTYPES en sqlite3.connect, entonces la conexión tratarán de convertir tipos de datos SQLite a los tipos de datos de Python cuando se dibuja datos de la base de datos.

Esta es una muy buena cosa ya que es mucho mejor para trabajar con objetos de fecha y hora que cadenas de fecha similar al azar que luego se tiene que analizar con datetime.datetime.strptime o dateutil.parser.parse.

Desafortunadamente, el uso detect_types no se detiene SQLite desde aceptar cadenas como datos de fecha, pero se obtendrá un error cuando intenta dibujar los datos de la base de datos (si se insertó en algún formato que no sea AAAA-MM-DD) porque la conexión fallará para convertirlo en un objeto datetime.date:

conn=sqlite3.connect(':memory:',detect_types=sqlite3.PARSE_DECLTYPES) 
cur=conn.cursor() 
cur.execute('CREATE TABLE foo(bar DATE)') 
# Unfortunately, this is still accepted by sqlite 
cur.execute("INSERT INTO foo(bar) VALUES (?)",('25/06/2003',)) 

# But you won't be able to draw the data out later because parsing will fail 
try: 
    cur.execute("SELECT * FROM foo") 
except ValueError as err: 
    print(err) 
    # invalid literal for int() with base 10: '25/06/2003' 
    conn.rollback() 

Pero al menos el error que alertará al hecho de que ha insertado una cadena para una FECHA en que realmente debería insertar fecha y hora.los objetos de fecha:

cur.execute("INSERT INTO foo(bar) VALUES (?)",(datetime.date(2003,6,25),)) 
cur.execute("SELECT ALL * FROM foo") 
data=cur.fetchall() 
data=zip(*data)[0] 
print(data) 
# (datetime.date(2003, 6, 25),) 

También pueden insertar cadenas como datos de fecha, siempre y cuando se utiliza el formato AAAA-MM-DD. Observe que aunque ha insertado una cadena, se vuelve a salir como un objeto datetime.date:

cur.execute("INSERT INTO foo(bar) VALUES (?)",('2003-06-25',)) 
cur.execute("SELECT ALL * FROM foo") 
data=cur.fetchall() 
data=zip(*data)[0] 
print(data) 
# (datetime.date(2003, 6, 25), datetime.date(2003, 6, 25)) 

Así que si eres disciplinado sobre la inserción de sólo datetime.date objetos en el campo DATE, entonces usted no tendrá problemas más adelante en la elaboración de la salida de datos

Si sus usuarios están ingresando datos de fecha en varios formatos, consulte dateutil.parser.parse. Es posible que pueda ayudarlo a convertir esas diversas cadenas en objetos datetime.datetime.

+0

Thanks unutbu - parece que los objetos de fecha son el camino a seguir. Saludos. –

5

Tenga en cuenta que SQLite no tiene un tipo de fecha/hora nativo. Como respondió @unutbu, puede hacer que el módulo pysqlite/sqlite3 intente adivinar (y tenga en cuenta que realmente es una suposición) qué columnas/valores son fechas/horas. Las expresiones SQL lo confundirán fácilmente.

SQLite tiene una variedad de funciones de fecha y hora y puede trabajar con varias cadenas, números en formato unixepoch y julian, y puede hacer transformaciones. Consulte la documentación:

http://www.sqlite.org/lang_datefunc.html

Puede que le resulte más conveniente para llegar SQLite para hacer el trabajo de fecha/hora que necesita en lugar de importar los valores en Python y el uso de bibliotecas de Python para hacerlo. Tenga en cuenta que puede poner restricciones en la definición de la tabla SQL por ejemplo requiriendo que el valor de cadena esté presente, sea una cierta longitud, etc.

+0

Gracias por la respuesta Roger. Revisaré esas funciones de fecha de SQLite. Saludos. –

Cuestiones relacionadas