SQLite дата хранения и преобразования - PullRequest
12 голосов
/ 25 ноября 2010

У меня проблемы с проектированием при хранении / извлечении дат с использованием Python и SQLite.

Я понимаю, что в столбце даты SQLite даты хранятся в виде текста в формате ISO (т. Е. '2010-05-25').Поэтому, когда я отображаю британскую дату (например, на веб-странице), я конвертирую дату, используя

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

Однако, когда дело доходит до записи данных в таблицу, SQLite очень простителен иочень рад хранить '25/06/2003' в поле даты, но это не идеально, потому что

  • Я мог бы остаться со смесью форматов даты в том же столбце,

  • Функции даты SQLite работают только с форматом ISO.

Поэтому мне нужно преобразовать строку даты обратно в формат ISO перед фиксацией, но тогда мне потребуется общийфункция, которая проверяет данные, которые должны быть записаны во все поля даты, и при необходимости преобразует их в ISO.Это звучит немного утомительно для меня, но, возможно, это неизбежно.

Есть ли более простые решения?Будет ли проще изменить поле даты на 10-символьное поле и хранить 'dd/mm/yyyy' по всей таблице?Таким образом, при чтении или записи из таблицы преобразование не требуется, и я мог бы использовать функции datetime (), если мне нужно было выполнить арифметику дат.

Как другие разработчики преодолели эту проблему?Любая помощь будет оценена.Для записи я использую SQLite3 с Python 3.1.

Ответы [ 2 ]

14 голосов
/ 25 ноября 2010

Если вы установите detect_types=sqlite3.PARSE_DECLTYPES в sqlite3.connect, тогда соединение попытается преобразовать типы данных sqlite в типы данных Python когда вы выводите данные из базы данных.

Это очень хорошая вещь, так как гораздо лучше работать с объектами datetime, чем случайные строки, похожие на даты, которые вы затем должны проанализировать datetime.datetime.strptime или dateutil.parser.parse.

К сожалению, использование detect_types не останавливает sqlite от принятия строки как данные DATE, но вы получите сообщение об ошибке при попытке вытянуть данные из базы данных (если они были вставлены в каком-либо формате, отличном от YYYY-MM-DD) потому что соединение не сможет преобразовать его в объект 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()

Но, по крайней мере, ошибка предупредит вас о том, что вы вставили строка для DATE, когда вам действительно нужно вставлять объекты datetime.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),)

Вы также можете вставлять строки в виде данных DATE, если вы используете формат ГГГГ-ММ-ДД. Обратите внимание, что хотя вы вставили строку, она возвращается как объект 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))

Так что, если вы дисциплинированно вставляете только datetime.date объекты в поле DATE, у вас не возникнет проблем при выводе данных позже.

Если ваши пользователи вводят данные даты в различных форматах, проверьте dateutil.parser.parse . Это может помочь вам преобразовать эти различные строки в datetime.datetime объекты.

5 голосов
/ 25 ноября 2010

Обратите внимание, что сам SQLite не имеет собственного типа даты / времени.Как ответил @unutbu, вы можете заставить модуль pysqlite / sqlite3 попытаться угадать (и заметьте, что это действительно предположение), какие столбцы / значения являются датами / временем.Выражения SQL могут легко запутать это.

SQLite имеет множество функций даты и времени и может работать с различными строками, числами как в unixepoch, так и в юлианском формате и может выполнять преобразования.См. Документацию:

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

Возможно, вам будет удобнее заставить SQLite выполнять работу с датой / временем, а не импортировать значения в Python и использовать библиотеки Python для выполненияЭто.Обратите внимание, что вы можете поместить ограничения в определение таблицы SQL, например, требующие наличия строкового значения, определенной длины и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...