【问题标题】:Shall I bother with storing DateTime data as julianday in SQLite?我应该麻烦在 SQLite 中将 DateTime 数据存储为 julianday 吗?
【发布时间】:2010-11-26 01:04:42
【问题描述】:

SQLite 文档指定在数据库中存储日期时间值的首选格式是使用 Julian Day(使用内置函数)。

但是,我在 python(pysqlite、SQLAlchemy)中看到的所有框架都将 datetime.datetime 值存储为 ISO 格式的字符串。他们为什么要这样做?

我通常会尝试调整框架以将日期时间存储为 julianday,这非常痛苦。我开始怀疑这是否值得。

请与我分享您在该领域的经验。坚持 julianday 有意义吗?

【问题讨论】:

    标签: python datetime sqlite sqlalchemy pysqlite


    【解决方案1】:

    Julian Day 对于各种日期计算都很方便,但它可以很好地存储 时间 部分(精确的小时、分钟和秒)。在过去,我使用了 Julian Day 字段(用于日期)和 seconds-from-the-Epoch(用于datetime 实例),但仅在我有特定的计算需求(日期和时间)时才使用。我认为 ISO 格式日期和日期时间的简单性应该使它们成为首选,比如大约 97% 的时间。

    【讨论】:

    • 所以我会坚持使用框架的默认设置,直到我有明确的理由不这样做。谢谢!
    • 能否请您描述一下为什么 julianday 的小时、分钟和秒精度不够好?
    • @Slava,考虑表示“1 秒”:一天的 1/86400.'th,它不能精确表示为双精度浮点数的小数部分,因为后者的表示在二进制形式和 86400 不是 2 的幂。
    • 目前(在 1029-09-15 和 6771-07-07 之间),存储为 double 的儒略日期的分辨率为 2**(-31) 天 ≅ 40.2 µs。
    【解决方案2】:

    以两种方式存储它。可以按照自己的方式设置框架,如果您希望找到一个带有 ISO 格式字符串的原始列,那么这可能比它的价值更痛苦。

    拥有两列的问题是数据一致性,但 sqlite 应该具备使其工作所需的一切。 3.3 版支持检查约束和触发器。阅读date and time functions。您应该能够完全在数据库中做您需要的事情。

    CREATE TABLE Table1 (jd, isotime);
    
    CREATE TRIGGER trigger_name_1 AFTER INSERT ON Table1
    BEGIN
        UPDATE Table1 SET jd = julianday(isotime) WHERE rowid = last_insert_rowid();
    END;
    
    CREATE TRIGGER trigger_name_2 AFTER UPDATE OF isotime ON Table1
    BEGIN
        UPDATE Table1 SET jd = julianday(isotime) WHERE rowid = old.rowid;
    END;
    

    如果你不能在数据库中做你需要的事情,你可以编写一个 C 扩展来执行你需要的功能。这样一来,除了加载扩展程序之外,您无需接触框架。

    【讨论】:

    • 感谢您的建议!这是一个好主意,它解决了我在这个问题上遇到的所有问题。
    • 为什么要想要以两种方式存储它?与 ISO 格式的字符串相比,存储儒略日的唯一真正优势是存储空间。如果您的框架需要 ISO 格式的字符串,请使用它。所有 SQLite 的 datetime functions 都可以处理 ISO 字符串,就像 julian days 一样。
    【解决方案3】:

    但通常,人类不会直接从数据库中读取数据。儒略日的小数时间很容易通过(例如)转换为人类可读的

    void hour_time(GenericDate *ConvertObject)
    {
        double frac_time    = ConvertObject->jd;
        double hour         = (24.0*(frac_time - (int)frac_time));
        double minute       = 60.0*(hour - (int)hour);
        double second       = 60.0*(minute - (int)minute);
        double microsecond  = 1000000.0*(second - (int)second);
    
        ConvertObject->hour         = hour;
        ConvertObject->minute       = minute;
        ConvertObject->second       = second;
        ConvertObject->microsecond  = microsecond;
    
    };
    

    【讨论】:

      【解决方案4】:

      因为2010-06-22 00:45:562455369.5318981484 更易于人类阅读。文本日期非常适合在 SQLiteSpy 或 SQLite Manager 中进行临时查询。

      当然,主要缺点是文本日期需要 19 个字节而不是 8 个字节。

      【讨论】:

        猜你喜欢
        • 2010-11-26
        • 2016-02-04
        • 2013-01-05
        • 2011-08-06
        • 2014-08-04
        • 2015-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多