简体   繁体   English

在sqlite3列中存储python datetime.time的最佳方法?

[英]Best way to store python datetime.time in a sqlite3 column?

I'm trying to replace my use of SAS with python + sqlite3; 我试图用python + sqlite3替换我对SAS的使用; I'm trying to move my data from SAS datasets to SQLite databases. 我正在尝试将数据从SAS数据集移动到SQLite数据库。 I have many time fields that are properly represented in python as datetime.time objects. 我有很多时间字段在python中正确表示为datetime.time对象。 Since SQLite is "lightly typed", I'm looking for advice about what format to use to store times in columns. 由于SQLite是“轻微键入”,我正在寻找有关用于在列中存储时间的格式的建议。 (I know I have to write python adapters etc. to read and write the objects to and from the column.) These are the features I need to consider: (我知道我必须编写python适配器等来读取和写入列中的对象。)这些是我需要考虑的功能:

  • SQLite's ability to deal with the column in queries. SQLite能够处理查询中的列。 (Eg will I be able to select out the rows that occur between two times?) (例如,我可以选择两次之间出现的行吗?)
  • Size of the field. 场地的大小。 (My tables are often hundreds of millions of rows.) (我的表通常是数亿行。)
  • Human readability. 人类可读性。 (I'm considering storing the time as an integer: microseconds since midnight. But this makes eyeballing the data harder.) (我正在考虑将时间存储为整数:自午夜以来的微秒。但这会使数据更难以观察。)

Has anyone solved this problem to their satisfaction? 有没有人解决这个问题令他们满意?

There is a general recipe for storing any serializable Python object in an sqlite table. 有一个通用的方法可以在sqlite表中存储任何可序列化的Python对象。

Here is what the code look might look like for datetime.time objects: 以下是datetime.time对象的代码外观:

import sqlite3
import datetime as DT

def adapt_timeobj(timeobj):
    return ((3600*timeobj.hour + 60*timeobj.minute + timeobj.second)*10**6 
            + timeobj.microsecond)

def convert_timeobj(val):
    val = int(val)
    hour, val = divmod(val, 3600*10**6)
    minute, val = divmod(val, 60*10**6)
    second, val = divmod(val, 10**6)
    microsecond = int(val)
    return DT.time(hour, minute, second, microsecond)


# Converts DT.time to TEXT when inserting
sqlite3.register_adapter(DT.time, adapt_timeobj)

# Converts TEXT to DT.time when selecting
sqlite3.register_converter("timeobj", convert_timeobj)

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()

# declare timecol to be of type timeobj
cur.execute("create table test (timecol timeobj)")

cur.executemany("insert into test (timecol) values (?)", 
                [(DT.time(1,2,3,4), ), (DT.time(5,6,7,8),) ])

You can use inequalities in the SQL, but note that the values being compared are those returned by adapt_timeobj , not the datetime.time objects. 您可以在SQL中使用不等式,但请注意,要比较的值是adapt_timeobj返回的adapt_timeobj而不是 datetime.time对象。 Fortunately, if the adapt_timeobj function returns integers that are orderable in the same order as the corresponding datetime.time objects (as they do above), then inequalities in the SQL will work as desired. 幸运的是,如果adapt_timeobj函数返回可以按相应的datetime.time对象的顺序排序的整数(如上所述),那么SQL中的不等式将按预期工作。

cur.execute("select timecol from test where timecol < ?",
            [DT.time(4,5,6)])
print(cur.fetchall())
# [(datetime.time(1, 2, 3, 4),)]

cur.execute("select timecol from test where timecol < ?",
            [DT.time(8,0,0)])
print(cur.fetchall())
# [(datetime.time(1, 2, 3, 4),), (datetime.time(5, 6, 7, 8),)]

con.commit()
cur.close()
con.close()

Note: If you look in the edit history, you'll see a simpler alternative for adapt_timeobj and convert_timeobj that stores the data as a str instead of as a int . 注意:如果查看编辑历史记录,您将看到adapt_timeobjconvert_timeobj的更简单的替代方法, adapt_timeobj数据存储为str而不是int It is simpler, but storing the data as a int is faster and more memory efficient. 它更简单,但将数据存储为int更快,内存效率更高。

I really like the answer by @unutbu but here's a simple way to store a timestamp. 我非常喜欢@unutbu答案 ,但这是一种存储时间戳的简单方法。

RFC 3339 is a very unambiguous timestamp format, easy for computers to parse and easy for humans to read. RFC 3339是一种非常明确的时间戳格式,便于计算机解析,便于人类阅读。 You could store timestamps as strings. 您可以将时间戳存储为字符串。

One nice property of RFC 3339: a simple ASCII sort also sorts chronologically. RFC 3339的一个不错的属性:简单的ASCII排序也按时间顺序排序。

But you don't really need the spec because it is so simple. 但你真的不需要这个规范,因为它很简单。 Here's an example: 这是一个例子:

2014-12-24T23:59:59.9999-08:00

That is the last fraction of a second before Christmas day in my time zone, which is 8 hours behind UTC (thus the -08:00 part). 这是我的时区圣诞节前一秒钟的最后一小部分,比UTC晚8小时(因此-08:00部分)。 Year, month, date, the string T , hour, minute, seconds, optional fractional second, timezone. 年,月,日,字符串T ,小时,分钟,秒,可选小数秒,时区。

The timezone may also be Z which indicates UTC time. 时区也可以是Z ,表示UTC时间。 But it's probably more convenient to store the times in the local time zone so you can read them more easily. 但是将时间存储在本地时区可能更方便,因此您可以更轻松地阅读它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM