C++ std::tm 从 std::chrono::time_point 转换后返回错误值

标签 c++ time chrono

TL;DR: 如何使用 std::chrono::system_clock::time_point仅基于某些参数进行比较(例如,我只想要小时、分钟和秒,而不是天、月等)。

另外:在转换 std::chrono::system_clock::time_point 之后到 std::tm , std::tm.tm_hours包含比 std::chrono::system_clock::time_point 的原始输入高 1 的值。 .

我获得 std::chrono::system_clock::time_point 的理论方法去工作:

typedef std::chrono::system_clock::time_point TimePoint;

TimePoint MainWindow::createTimePoint(int h, int m)
{
    TimePoint createdTime = std::chrono::system_clock::time_point{std::chrono::hours(h) + std::chrono::minutes(m)};

    time_t tt = std::chrono::system_clock::to_time_t(createdTime);
    tm timeExtracted = *localtime(&tt);

    std::cout << "input:\t\t" << "H = " << h << ", M = " << m << std::endl; 
    std::cout << "timeExtracted:\t" << "H = " << timeExtracted.tm_hour << ", M = " << timeExtracted.tm_min << std::endl; 

    return createdTime;
}

如果我运行它,timeExtracted 的小时数总是 +1 从输入 h .

为什么呢?以及如何解决这个问题? 我浏览了其他一些显示这一点的帖子,但他们无法帮助我。大概也是因为这个:

我认为当我创建 TimePoint 、日、月等也设置为随机值或初始化为某个值。关键是:我希望它们始终是相同的值,这样我的 TimePoint (转换后)基本上显示了这一点:
timeExtracted.tm_sec = 0
timeExtracted.tm_min = m
timeExtracted.tm_hour = h
timeExtracted.tm_mon = 0
timeExtracted.tm_wday = 0
timeExtracted.tm_mday = 0
timeExtracted.tm_yday = 0
timeExtracted.tm_year = 0
timeExtracted.tm_isdst = 0

我如何比较其中两个 TimePoint利用对它们使用 std::chrono 的比较操作,但只比较小时和分钟。

如果我的问题不清楚,对不起,已经很晚了。我明天早上再检查一次。谢谢你。

最佳答案

我将开始一个答案,但这不会是一个完整的答案,因为我还不确定完整的问题。不过,我可以帮忙。

TimePoint createdTime = system_clock::time_point{hours(h) + minutes(m)};

(我剪掉了 std::chrono:: 限定词,以便更容易阅读和讨论)

这将创建一个时间戳,即 1970-01-01 hh:mm:00 UTC。简而言之,system_clock::time_point正在测量自 1970 年新年(UTC)以来的持续时间(以微秒或纳秒等某些单位为单位)。从技术上讲,以上是一个近似值,system_clock不计算闰秒,但我们现在可以(并且应该)忽略这个细节。

这:
tm timeExtracted = *localtime(&tt);

将根据您计算机的本地时区设置引入 UTC 偏移校正。时区调整规则(希望)将基于您所在地区 1970 年生效的规则。

存在用于获取 system_clock::time_point 的技术和库并将其分解为 {year, month, day, hours, minutes, seconds, microseconds} 等字段.但这种转换还取决于您是否希望这些字段采用 UTC、本地时间或其他任意时区。

如果需要,第一步是应用与某个时区相关的 UTC 偏移量。可能是您的{h, m}输入需要在将它们放入 system_clock::time_point 之前进行 UTC 偏移调整如果意图是 {h, m}代表本地时间而不是 UTC。

更新:商店营业时间示例

这个例子将使用我的 free, open-source time zone library ,因为我觉得它更容易使用,并且允许更具可读性和表现力的代码。

此示例将 system_clock::time_point 作为输入并将其与一周中每一天的打开/关闭时间列表进行比较,并确定输入时间是否在与输入时间相关的工作日的那些时间范围之内或之外 t .假定商店营业时间是相对于商店的本地时区来说明的,这也是为运行此代码的计算机设置的当前时区。
#include "date/tz.h"

#include <algorithm>
#include <cassert>
#include <chrono>

bool
is_store_open_at(std::chrono::system_clock::time_point tp)
{
    using namespace date;
    using namespace std::chrono;

    struct day_schedule
    {
        weekday wd;
        minutes open;
        minutes close;
    };

    // hours are expressed in terms of local time
    static constexpr day_schedule store_hours[]
    {
      // week day   open-time   close-time
        {Monday,    0h,                0h},  // closed all day
        {Tuesday,   8h,               18h},
        {Wednesday, 8h,               18h},
        {Thursday,  8h,               18h},
        {Friday,    8h,               18h},
        {Saturday,  8h,         15h+30min},
        {Sunday,    9h+30min,         15h}
    };

    auto local_tp = current_zone()->to_local(tp);
    auto local_day = floor<days>(local_tp);
    auto local_time_of_day = local_tp - local_day;
    weekday local_weekday{local_day};
    auto ds = std::find_if(std::begin(store_hours), std::end(store_hours),
                           [local_weekday](day_schedule const& x)
                           {
                               return x.wd == local_weekday;
                           });
    assert(ds != std::end(store_hours));
    return ds->open <= local_time_of_day && local_time_of_day < ds->close;
}

#include <iostream>

int
main()
{
    std::cout << is_store_open_at(std::chrono::system_clock::now()) << '\n';
}

该函数首先定义一些方便的数据结构来存储一周中每一天的打开和关闭时间。 openclose day_schedule 的成员以本地时间测量“自午夜以来的分钟数”。

输入时间tp以 UTC 表示,因为它的类型是 system_clock::time_point . C++ 标准目前没有规定这一点,但明年的 C++20 会规定这一点。
zoned_seconds用于转换UTC时间t根据调用current_zone()获取的计算机时区设置转换为本地时间.我已截断 t到秒来简化一些语法。这不是绝对必要的。我已经编辑使用稍微简单的语法来消除 zoned_seconds . zoned_seconds在其他示例中可能非常有用,但在这个示例中,麻烦多于其值(value)。 auto local_tp = current_zone()->to_local(tp)是将 UTC 转换为本地时间点的更简单方法。
local_tpchrono::time_point被认为是“本地时间”,与 chrono::time_point 的系列不同。 s 与 system_clock 相关联.这样做的好处是,如果本地时间和 UTC 时间意外混合,这是一个编译时错误。
local_days简直是local_tp截断为 days精确。它仍然是 chrono::time_point ,只是一个粗略的,它指向本地时区描述的一天的开始。

从本地午夜开始的持续时间只是 local_tp - local_day .

星期几(由本地时区定义)可以通过转换 local_day 获得输入 weekday .这是与 tp 相关的本地星期几.

现在搜索store_hours是一件简单的事情对于匹配 local_weekday 的条目.

如果 local_time_of_day 则商店营业等于或超过 open时间还没到close时间。

如果“商店营业时间”指定为 UTC 而不是本地时间,则此程序会稍微简化一些,但仍然相似。

关于C++ std::tm 从 std::chrono::time_point 转换后返回错误值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57718779/

相关文章:

c++ - 强类型 C++0x 枚举比较

c++ - (C++)如果我在一个类中声明了一些私有(private)的东西,但它可以通过类的公共(public)方法改变,那我为什么要声明它私有(private)?

time - 带有时间盐的客户端 MD5 哈希

javascript - 在 Angular js过滤器中格式化时间

C++20 格式 sys_time,精度为毫秒

c++ - 两个日期之间的秒数,包括闰秒

c++ - 在头文件重新定义错误中包含 .cpp - 实现通用堆栈

c++ - 如何专门化 'partially'成员方法?

unix - 'real' 、 'user' 和 'sys' 在 time(1) 的输出中是什么意思?

c++ - VS11是steady_clock,稳定吗?