【问题标题】:SQLite date storage and conversionSQLite 日期存储和转换
【发布时间】:2015-02-20 06:35:26
【问题描述】:

我在使用 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 一起使用。

【问题讨论】:

    标签: python sqlite


    【解决方案1】:

    如果您在sqlite3.connect 中设置detect_types=sqlite3.PARSE_DECLTYPES, 然后连接将尝试将 sqlite 数据类型转换为 Python 数据类型 当您从数据库中提取数据时。

    这是一件非常好的事情,因为它比使用 datetime 对象要好得多 然后您必须解析的随机日期字符串 datetime.datetime.strptimedateutil.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()
    

    但至少该错误会提醒您已插入的事实 当您确实应该插入 datetime.date 对象时,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),)
    

    只要您使用 YYYY-MM-DD 格式,您也可以插入字符串作为 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 对象。

    【讨论】:

    • 感谢 unutbu - 看起来日期对象是要走的路。问候。
    【解决方案2】:

    请注意,SQLite 本身没有本机日期/时间类型。正如@unutbu 回答的那样,您可以让 pysqlite/sqlite3 模块尝试猜测(并注意它确实是猜测)哪些列/值是日期/时间。 SQL 表达式很容易混淆它。

    SQLite 确实有各种日期时间函数,可以处理各种字符串、unixepoch 和 julian 格式的数字,并且可以进行转换。请参阅文档:

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

    您可能会发现让 SQLite 完成您需要的日期/时间工作比将值导入 Python 并使用 Python 库来完成更方便。请注意,您可以在 SQL 表定义中设置约束,例如要求字符串值存在、一定长度等。

    【讨论】:

    • 感谢罗杰的回复。我将检查那些 SQLite 日期函数。问候。
    猜你喜欢
    • 1970-01-01
    • 2016-09-22
    • 2010-11-23
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    相关资源
    最近更新 更多