首页 > 解决方案 > 没有日期的 C++ 时间?

问题描述

在 C++ 中处理没有日期的时间点的最佳方法是什么?

我有没有日期的时间戳。时间戳是 24 小时军用时间,没有日期、时区或其他信息。时间戳存储为字符串。

我需要完成两个任务:

  1. 存储时间戳表示的时间数据。
  2. 计算时间之间的差异。

我知道 C++ 有带有时间数据结构的库。其中一些数据结构包括有关日期的信息。如果可能的话,我不想使用那些类型的数据结构,因为我的数据不包括日期。我想要类似于时间数据结构的功能

但除了 24 小时军用时间(显式或隐式)外,没有任何日期或其他任何存储。

我想要不存储有关日期或除 24 小时军用时间以外的任何信息的时间点对象。我想要

  1. 将我的时间戳字符串转换为这些对象。

然后

  1. 查找结果时间点之间的差异(时间点之间的持续时间)。

实现这一目标的最佳方法是什么?

我的理想解决方案涉及现有的标准或 Boost 库,并避免存储有关日期、时区或 24 小时军用时间以外的任何信息。我可能忽略了我已经提到的库之一(即 Boost.Date_Time、chrono 或 ctime)可能会满足我的需求。

标签: c++time

解决方案


一个想法是创建一个自定义chrono时钟,可能会调用time_of_day_clock它,然后创建一个chrono::time_points 家族。或者也许你只需要seconds-precision 时间(你不清楚)。以下是在这样的时钟上创建seconds-precision所需的全部内容:time_point

struct time_of_day_clock {};
using time_of_day = std::chrono::time_point<time_of_day_clock,
                                            std::chrono::seconds>;

现在您可以创建几个辅助函数在 and 之间std::string进行转换time_of_day

// Assume t is of the form HH:MM:SS
time_of_day
to_time_of_day(const std::string& t)
{
    using namespace std::chrono;
    auto parse = [&t](auto i) -> int
        {
            return (t[i]-'0')*10 + (t[i+1]-'0');
        };
    hours h{parse(0)};
    minutes m{parse(3)};
    seconds s{parse(6)};
    return time_of_day{h+m+s};
}

// Format to HH:MM:SS
std::string
to_string(const time_of_day& t)
{
    using namespace std;
    using namespace std::chrono;
    auto s = t.time_since_epoch();
    assert(s >= 0s);
    assert(s < 86400s);
    auto h = duration_cast<hours>(s);
    s -= h;
    auto m = duration_cast<minutes>(s);
    s -= m;
    string r = "00:00:00";
    auto print = [&r](auto i, auto j)
        {
            for (++j; i != 0; i /= 10, --j)
                r[j] = i % 10 + '0';
        };
    print(h.count(), 0);
    print(m.count(), 3);
    print(s.count(), 6);
    return r;
}

现在您拥有执行以下操作的所有工具:

int
main()
{
    auto t1 = to_time_of_day("17:15:23");
    auto t2 = to_time_of_day("07:14:06");
    std::cout << "t1 = " << to_string(t1) << '\n';
    std::cout << "t2 = " << to_string(t2) << '\n';
    auto d = t1 - t2;
    std::cout << d.count() << "s\n";
    auto t3 = t2 + d;
    std::cout << "t3 = " << to_string(t3) << '\n';
}

输出:

t1 = 17:15:23
t2 = 07:14:06
36077s
t3 = 17:15:23

这为您提供类型安全: 一天中的时间不会与持续时间混淆,但它们与有理代数互操作。

根据您的应用程序的需要/要求,在上面添加尽可能多的错误检查。

上述计划有一个小问题:语言律师可能会抱怨整个事情是未定义的行为,因为time_of_day_clock不符合计时时钟要求。

现实情况是,除非您尝试调用 ,否则一切都会正常工作now()time_of_day_clock或者time_of_day与尝试这样做的算法一起使用(或尝试访问嵌套类型的time_of_day_clock)。如果您不小心这样做了,结果将是编译时错误,而不是运行时错误,也不是未定义的行为。

我认为对Clock模板参数的要求time_point过于严格,并将尝试将它们减少到未来标准中的实际要求


推荐阅读