如何判断它是否在 C++ 中的配置时间之前?

How to tell if it's before a configured time in C++?

我正在尝试找到查看当前时间是否早于指定时间的最佳方法。假设我想看看它是否在 14:32 之前。在 C++ 中执行此操作的最佳方法是什么?理想情况下,我能够构建一些表示 14:32 的时间对象,然后将其与作为某个对象的当前时间进行比较。 这就是我现在正在做的。相当混乱,使用了 3 种不同的时间表示法。

int hour_ = 14;
int min_ = 32;
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t tt = std::chrono::system_clock::to_time_t(now);
std::tm utc_tm = *gmtime(&tt);
if ((utc_tm.tm_hour < hour_) || (utc_tm.tm_hour == hour_ && utc_tm.tm_min < min_) ) {
    std::cout << "It's before " << hour_ << ":" << min_ << std::endl;
}

在 C++ 中,我们可以使用 date/time 函数中的 mt_structure(此处的文档:https://en.cppreference.com/w/cpp/chrono/c/tm)这是我打印日期并检查日期是否已过的方法某个时候

#include <iostream>
#include <ctime>
#include <chrono>
using namespace std;

int main()
{
  time_t t = time(0);   // get time now
    tm* now = localtime(&t);
    cout << (now->tm_year + 1900) << '-' 
        << (now->tm_mon + 1) << '-'
        <<  now->tm_mday << ", " 
        << now->tm_hour << ":" << now->tm_min
        << "\n";

  int hour = 7, minute = 30;
  if((now->tm_hour > hour) || (now->tm_hour == hour && now->tm_min >= minute))
    cout << "it's past 7:30\n";
  else 
    cout << "it's not past 7:30";
}
  

打印:

2021-10-27, 20:40
it's past 7:30

这是在 C++20 中的实现方法。稍后我将展示如何将其转换为使用适用于 C++11/14/17 的 free, open-source C++20 chrono preview library

#include <chrono>

bool
is_now_before(std::chrono::minutes local_config_tod)
{
    using namespace std::chrono;

    auto tz = current_zone();
    auto now = system_clock::now();

    auto local_day = floor<days>(zoned_time{tz, now}.get_local_time());
    auto utc_config = zoned_time{tz, local_day + local_config_tod}.get_sys_time();
    return now < utc_config;
}

该参数的类型为 minutes,它将被解释为本地时间(以分钟为单位)。例如 14:32 表示为 minutes{872}。这种表示是紧凑的(一个整数),将 {hours, minutes} 转换为 minutes 很简单(如下所示)。

current_zone() 获取计算机当前的本地时区。在此函数中需要两次此信息,因此最好只获取一次。这不仅保存了结果,而且还避免了本地时区在移动设备中从您下方(在多个呼叫之间)发生变化的问题。

接下来通过system_clock获取当前时间(仅一次)。这给出了 UTC 的当前时间。

现在我们有一个选择:

  1. 我们可以在 UTC 中进行比较,或者
  2. 我们可以在当地时间进行比较。

在 UTC 偏移量在当前本地日期发生变化(例如夏令时开启或关闭)的极端情况下,以 UTC 进行比较不太容易出错。

要将本地配置 time-of-day (local_config_tod) 转换为 UTC time_point,首先必须找出当前本地日期。通常,这可能不同于当前的 UTC 日期。所以当前UTC now 必须转换为本地时间,然后截断为 days-precision:

auto local_day = floor<days>(zoned_time{tz, now}.get_local_time());

现在可以简单地通过将 local_daylocal_config_tod 相加来创建本地 time_point。然后可以将此本地 time_point 转换回 UTC(基于 system_clock 但具有 seconds 精度的 time_point):

auto utc_config = zoned_time{tz, local_day + local_config_tod}.get_sys_time();

上面的代码行为您处理极端情况。如果不存在从本地时间到 UTC 的唯一 (one-to-one) 映射,则会抛出异常。异常类型的.what()会有详细的描述,这个映射要么是有歧义的,要么是non-existent.

假设上面的映射没有抛出异常,你可以简单的比较这两个UTC time_points:

return now < utc_config;

此比较的精度与您的 system_clock 具有的任何精度(通常为微秒到纳秒)。

可以这样练习:

int hour_ = 14;
int min_ = 32;
using namespace std::chrono;
auto b = is_now_before(hours{hour_} + minutes{min_});

如果 14 和 32 是文字(并且您使用的是 C++14 或更高版本),则可以将其缩短为:

auto b = is_now_before(14h + 32min);

如果您使用的是 C++17 之前的标准,zoned_time 构造将需要显式模板参数:

auto local_day = floor<days>(zoned_time<system_clock::duration>{tz, now}.get_local_time());
auto utc_config = zoned_time<minutes>{tz, local_day + local_config_tod}.get_sys_time();

如果您想使用 free, open-source C++20 chrono preview library,请添加 #include "date/tz.h"using namespace date;需要一些安装

如果您想在 local_day + local_config_tod 没有到 UTC 的唯一映射的情况下避免异常,也可以对 is_now_before 进行微小的更改。但是您必须决定以下事项:我是否要与 local_day 的第一个或第二个 local_config_tod 进行比较(以防 UTC 偏移量已减少)。

糟糕!配置时间已经是UTC了吗?

关于 re-reading 你的问题我突然想到我可能误读了你的问题。如果 14:32 是 UTC,那么事情会变得 muchmuch 简单!与其删除显示本地 14:32 解释的答案,我认为最好添加这个,以便未来的读者可以选择任何一种解决方案。

假设配置是 UTC 时间,那么时区根本不起作用:

#include <chrono>

bool
is_now_before(std::chrono::minutes utc_config_tod)
{
    using namespace std::chrono;

    auto now = system_clock::now();

    auto utc_day = floor<days>(now);
    return now < utc_day + utc_config_tod;
}

UTC 中的当前日期是:

auto utc_day = floor<days>(now);

现在配置 date-time 只是 utc_day + utc_config_tod。这只是drop-dead简单。

如果你不能使用 C++20,free, open-source C++20 chrono preview library 现在也比 header-only 简单得多,需要 no 安装在全部。只需 #include "date/date.h" 并添加 using namespace date;.