提问人:ulfben 提问时间:11/23/2022 最后编辑:Jarod42ulfben 更新时间:11/24/2022 访问量:195
如何使用 STL 表示 24 小时制?
How do I represent a 24-hour clock with the STL?
问:
我正在寻找 STL 的解决方案,用于处理“一天中的时间”。我正在做一个简单的单元测试练习,其行为取决于当前时间是早上、晚上还是晚上。
在第一次迭代中,我使用了一个不起眼的整数作为某个“时间对象”的替身:
using TimeOfDay = int;
constexpr bool isBetween(TimeOfDay in, TimeOfDay min, TimeOfDay max) noexcept {
return in >= min && in <= max;
}
constexpr bool isMorning(TimeOfDay in) noexcept {
return isBetween(in, 6, 12); }
constexpr bool isEvening(TimeOfDay in) noexcept {
return isBetween(in, 18, 22);
}
constexpr bool isNight(TimeOfDay in) noexcept {
return isBetween(in, 22, 24) || isBetween(in, 0, 6);
}
constexpr string_view getGreetingFor(TimeOfDay time) noexcept {
if (isMorning(time)) {
return "Good morning "sv;
}
if (isEvening(time)) {
return "Good evening "sv;
}
if (isNight(time)) {
return "Good night "sv;
}
return "Hello "sv;
}
这可行,但有几种气味:
- 根本不是表示 24 小时制的正确类型
int
isNight()
由于换行,需要不必要的复杂比较 (22-06)- 理想情况下,我希望能够实际使用系统时钟进行一些测试。
std::chrono::system_clock::now()
返回一个 ,所以我的理想类型可能应该是可以与 比较的东西,或者很容易从 .std::chrono::time_point
time_point
time_point
任何指点将不胜感激!
(我正在使用 C++Latest 在 Visual Studio 中工作(C++ 工作草案的预览,所以大致是 C++23))
答:
如果您谈论的是一天内的时间,与日期无关,请使用 std::chrono::d uration
。对于整数小时,有别名 。std::chrono::hours
像这样的东西:
#include <iostream>
#include <chrono>
using namespace std::chrono;
int main()
{
auto now = system_clock::now().time_since_epoch();
auto today = duration_cast<days>(now);
hh_mm_ss time { now - today };
std::cout << time.hours() << time.minutes() << time.seconds();
}
评论
floor
duration_cast
“一天中的时间”应存储在 .要仅分离任何 的 h/m/s 信息,您可以执行以下操作:std::chrono::duration
duration
auto time_info = my_duration - std::chrono::round<std::chrono::days>(my_duration);
同样,您可以分离具有相同接口的 的 h/m/s 信息:time_point
auto now = std::chrono::system_clock::now();
auto time_info = now - std::chrono::round<std::chrono::days>(now);
然后,可以使用帮助程序类来检查信息:hh_mm_ss
auto hms = std::chrono::hh_mm_ss{ time_info };
std::cout << hms.hours() << hms.minutes() << hms.seconds();
要检查 a 是否介于其他两个时间之间,您可以执行以下操作:duration
using TimeOfDay = std::chrono::seconds;
constexpr bool isBetween(TimeOfDay in, TimeOfDay min, TimeOfDay max) noexcept {
return in >= min && in <= max;
}
constexpr bool isMorning(TimeOfDay in) noexcept {
return isBetween(in, std::chrono::hours{6}, std::chrono::hours{12});
}
您还可以通过以下方式启用文本:using namespace std::chrono_literals
using namespace std::literals
constexpr bool isMorning(TimeOfDay in) noexcept {
return isBetween(in, 6h, 12h);
}
对于包装,您可以执行以下操作: ,但我认为您现在拥有的逻辑更简洁,更容易遵循。isEvening
isBetween(in + 12h - days{1}, 10h, 18h)
如果需要,这可以很容易地转回:time_point
auto today = std::chrono::round<std::chrono::days>(std::chrono::system_clock::now());
auto now = today + time_info;
我将从您正在寻找一天中的当地时间的假设开始。 表示 UTC。因此,我推荐一个辅助函数,它接受并返回一个表示自最近一个本地午夜以来经过的时间:chrono::system_clock
std::chrono::system_clock::time_point
std::chrono::system_clock::duration
using TimeOfDay = std::chrono::system_clock::duration;
TimeOfDay
get_local_time_of_day(std::chrono::system_clock::time_point tp) noexcept
{
using namespace std::chrono;
auto time = current_zone()->to_local(tp);
return time - floor<days>(time);
}
chrono::current_zone()
返回指向计算机当前设置为的指针。这用于将 转换为本地 .这个本地是一个,但具有不同的时钟,意思是“本地时间”。chrono::time_zone
system_clock::time_point
time_point
time_point
chrono::time_point
该表达式截断了 精度 ,这有效地为您提供了指向最近传递的本地午夜的指针。减去它,你就会得到一个自当地午夜以来的。这将具有与 相同的精度。floor<days>(time)
time_point
days
time
chrono::duration
duration
tp
此功能无法制作,因为将 UTC 转换为当地时间的规则掌握在您的政客手中,并且可能会发生变化(在许多国家/地区每年两次!constexpr
现在你可以这样写(et al):isMorning
bool isMorning(std::chrono::system_clock::time_point in) noexcept {
using namespace std::literals;
return isBetween(get_local_time_of_day(in), 6h, 12h); }
并这样称呼它:
if (isMorning(system_clock::now())) ...
你的逻辑在我看来很好。并且您的代码可以保持原样(选择 的新定义)。isNight
isBetween
TimeOfDay
下一个:标准库中存在特定标头
评论
TimeOfDay
Hour
TimeOfDay
isNight(
) 需要不必要的复杂比较,由于换行 (22-06)”您可以反转比较:.return not isBetween(in, 7, 21);