【问题标题】:C++ and Sqlite3: How to store date/time with milliseconds precisionC++ 和 Sqlite3:如何以毫秒精度存储日期/时间
【发布时间】:2015-09-23 18:36:55
【问题描述】:

我正在构建一个将在 Ubuntu 中运行并将使用 Sqlite3 作为数据库的 C++ 应用程序。

我的目标之一是创建一个包含时间/日期字段的 C++ 类,然后将其存储在数据库中。

过去我在我的类中使用 time_t 作为变量类型,并将它们存储为 Sqlite3 上的 INTEGER 类型,例如:

C++ 类:

class MyClass {

        time_t dateTimeInfo;
}

Sqlite3:

CREATE TABLE MYCLASS (....., INTEGER DATETIMEINFO, ...);

这种方法允许我使用不同的比较运算符 (>, >=, < , <=, ==) 进行SELECT 次,因为我正在处理简单的数字。在用户级别,time_t 被转换为 ISO 8601 std::string´s,这样我就可以拥有一个人类可读的界面。

这很好用,只是它不支持毫秒数。在我当前的项目中,我需要支持他们,所以我需要对此进行更改。

据我所知,我需要使用 std::chrono::time_point 作为类类型,如下所示:

C++ 类:

class MyClass {

        std::chrono::time_point dateTimeInfo;
}

但我真的不知道在 Sqlite3 中使用什么数据类型,以及它是否会像 time_t 过去那样工作......

Sqlite3:

CREATE TABLE MYCLASS (....., ???? DATETIMEINFO, ...);

我的问题:

a) std::chrono::time_point 是这里的正确选项吗?

b) Sqlite3 类型等价物是什么?还是INTEGER

c) 这是推荐的方法吗(请不要boost,C++11)?

感谢您的帮助。

【问题讨论】:

  • 您可以将 ISO 8601 格式直接存储为字符串,并使用普通比较运算符进行比较,只要您的比较字符串也是 ISO 格式。你尝试过吗?

标签: c++ c++11 sqlite chrono


【解决方案1】:

是的,std::chrono 是一个非常好的方法(内部使用 C++)。您可以像这样使用std::chrono 将时间点从/到毫秒转换:

using namespace std::chrono;

typedef time_point<system_clock, milliseconds> time_points_millis;

time_points_millis tp = system_clock::now();

// An at least 43 bit signed integral type
auto epoch = tp.time_since_epoch();

在这种情况下,您应该使用 64 位整数类型来使用 SQLite 存储它,因为数据可能超过 32 位。

评论:我对 SQLite 还不是很了解,但我发现它适用于 64 位类型:official docs

【讨论】:

    【解决方案2】:

    您可以将 ISO 8601 字符串格式的时间直接存储为TEXT。例如,您可以制作下表:

    CREATE TABLE tbl(name TEXT, ts TEXT);
    

    并插入 ISO 8601 格式的字符串毫秒值作为文本字符串:

    INSERT INTO tbl VALUES ('first', '2015-07-06T10:59:46.1234Z');
    INSERT INTO tbl VALUES ('second', '2015-07-06T10:59:47.5678Z');
    INSERT INTO tbl VALUES ('third', '2015-07-06T10:59:48.9012Z');
    

    此时您可以使用比较运算符查询它们:

    SELECT * FROM tbl WHERE ts <= '2015-07-06T10:59:46.1233Z';
    // Returns nothing
    SELECT * FROM tbl WHERE ts <= '2015-07-06T10:59:46.1234Z';
    // Returns the first record
    SELECT * FROM tbl WHERE ts > '2015-07-06T10:59:46.1234Z';
    // Returns the last two records
    

    作为额外的奖励,当您与此数据库交互时,您会在退出时获得 ISO 8601 格式,这就是您在客户端所做的事情。

    此方法利用了这样一个事实,即在时区内,字符串的字典顺序会产生语义上正确的日期时间顺序。如果您的使用场景涉及多个时区,则使用单个时区(例如 UTC 时间)存储在数据库中有助于保留此排序属性。

    【讨论】:

    • 发现这种方法存在时区问题:SELECT * FROM tbl WHERE ts &gt; '2015-07-06T10:59:46.1234-03:00';SELECT * FROM tbl WHERE ts &gt; '2015-07-06T10:59:46.1234-05:00'; 都返回 secondthird,这不是预期的行为...
    • 您说的完全正确,ISO 8601 是按字典顺序在时区内排序的,而不是在时区之间。要获得纯排序,您必须将日期时间字符串存储为 UTC 时间。我会在我的回答中通过编辑来澄清这一点。
    猜你喜欢
    • 2017-06-13
    • 2021-01-23
    • 1970-01-01
    • 2017-08-31
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    相关资源
    最近更新 更多