2010-11-25 6 views
12

J'ai des problèmes de conception avec le stockage/extraction de date en utilisant Python et SQLite.Stockage et conversion de date SQLite

Je comprends qu'une colonne de date SQLite stocke des dates sous forme de texte au format ISO (c'est-à-dire '2010-05-25'). Alors, quand j'afficher une date britannique (par exemple. Sur une page Web) Je convertir la date en utilisant

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

Cependant, en matière de données écriture à la table, SQLite est très pardonner et est très heureux de stocker '25/06/2003' dans un champ de date, mais ce est pas idéal car

  • Je pourrais être laissé avec un mélange de formats de date dans la même colonne ,

  • Les fonctions de date de SQLite fonctionnent uniquement avec le format ISO.

donc je besoin de convertir la chaîne de date de retour au format ISO avant commettre, mais je aurais besoin d'une fonction générique qui vérifie les données sur le être écrites dans tous les domaines de la date et convertit ISO si nécessaire. Cela me semble un peu ennuyeux, mais c'est peut-être inévitable.

Existe-t-il des solutions plus simples? Serait-il plus facile de changer le champ de date en champ de 10 caractères et de stocker 'dd/mm/yyyy' dans tout le tableau? De cette façon, aucune conversion n'est requise lors de la lecture ou de l'écriture à partir de la table, et je pourrais utiliser les fonctions datetime() si j'avais besoin d'effectuer une date-arithmétique.

Comment d'autres développeurs ont-ils surmonté ce problème? Toute aide serait appréciée. Pour l'anecdote, j'utilise SQLite3 avec Python 3.1.

Répondre

14

Si vous définissez detect_types=sqlite3.PARSE_DECLTYPES dans sqlite3.connect, alors la connexion va essayer de convertir les types de données SQLite pour les types de données Python lorsque vous dessinez des données sur la base de données.

C'est une très bonne chose car il est beaucoup plus agréable de travailler avec des objets datetime que chaînes de date comme aléatoires que vous avez alors à analyser avec datetime.datetime.strptime ou dateutil.parser.parse.

Malheureusement, l'utilisation detect_types ne se limite pas sqlite de accepter chaînes en tant que données DATE, mais vous obtiendrez une erreur lorsque vous essayez de tirer les données de la base de données (si elle a été insérée dans un format autre que AAAA-MM-JJ) car la connexion ne parviendra pas à le convertir en un objet 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() 

Mais au moins l'erreur vous alerter sur le fait que vous avez inséré une chaîne pour une DATE lorsque vous devriez vraiment insérer datetime.objets de date:

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),) 

Vous pouvez également insérer des chaînes en tant que données de date, tant que vous utilisez le format AAAA-MM-JJ. Notez que même si vous avez inséré une chaîne, il revient comme un objet 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)) 

Donc, si vous êtes discipliné sur l'insertion d'objets seulement datetime.date dans le champ DATE, alors vous aurez pas de problèmes plus tard lors de l'élaboration du données sortantes.

Si vos utilisateurs sont des données de date d'entrée-ment dans différents formats, consultez dateutil.parser.parse. Il peut être en mesure de vous aider à convertir ces différentes chaînes en objets datetime.datetime.

+0

Merci unutbu - ressemble à des objets de date sont le chemin à parcourir. Cordialement. –

5

Notez que SQLite lui-même ne dispose pas d'un type de date/heure d'origine. Comme @unutbu a répondu, vous pouvez faire le module pysqlite/sqlite3 essayer de deviner (et notez qu'il est vraiment une supposition) les colonnes/valeurs sont les dates/heures. Les expressions SQL vont facilement le confondre.

SQLite a une variété de fonctions de date et heure et peuvent travailler avec différentes chaînes, les chiffres dans les unixepoch et le format julian, et peut faire des transformations. Consultez la documentation:

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

Vous trouverez peut-être plus pratique pour obtenir SQLite faire la date/heure de travail dont vous avez besoin au lieu d'importer les valeurs en Python et en utilisant les bibliothèques Python pour le faire. Notez que vous pouvez mettre dans la définition des contraintes de table SQL par exemple exigeant que la valeur de chaîne soit présent, une certaine longueur, etc.

+0

Merci pour la réponse Roger. Je vais vérifier ces fonctions de date SQLite. Cordialement. –