如何判断它是否在 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 的当前时间。
现在我们有一个选择:
- 我们可以在 UTC 中进行比较,或者
- 我们可以在当地时间进行比较。
在 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_day
和 local_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_point
s:
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,那么事情会变得 much、much 简单!与其删除显示本地 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;
.
我正在尝试找到查看当前时间是否早于指定时间的最佳方法。假设我想看看它是否在 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 的当前时间。
现在我们有一个选择:
- 我们可以在 UTC 中进行比较,或者
- 我们可以在当地时间进行比较。
在 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_day
和 local_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_point
s:
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,那么事情会变得 much、much 简单!与其删除显示本地 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;
.