有趣的事实,我相信我们大多数在时间领域玩游戏的人都知道——有些日期/时间看起来有效,但实际上并不存在,例如夏令时凌晨2:30。
在C++(标准或Windows)中,有没有办法确定给定的日期/时间在给定的时区规范中是否有效?
使用Windows特定的函数,可以调用TzSpecificLocalTimeToSystemTime()
,然后调用具有相关时区的SystemTimeToTzSpecificLocalTime()
。
完成后,如果两者不同,则会有一个无效时间,因为TzSpecificLocalTimeToSystemTime
会将无效时间转换为"真实"时间。
bool IsValidTime(TIME_ZONE_INFORMATION tz, SYSTEMTIME st)
{
SYSTEMTIME utcSystemTime, st2;
TzSpecificLocalTimeToSystemTime(&tz, &st, &utcSystemTime);
SystemTimeToTzSpecificLocalTime(&tz, &utcSystemTime, &st2);
return (st != st2);
}
使用这个免费的开源库:
#include "tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono_literals;
try
{
auto zone = locate_zone("America/New_York");
zone->to_sys(local_days{mar/13/2016} + 2h + 30min);
}
catch (const std::exception& e)
{
std::cout << e.what() << 'n';
}
}
该程序的输出为:
2016-03-13 02:30 is in a gap between
2016-03-13 02:00:00 EST and
2016-03-13 03:00:00 EDT which are both equivalent to
2016-03-13 07:00:00 UTC
简而言之,此程序尝试使用时区"America/New_York"将区域设置日期/时间2016-03-13 02:30:00翻译为UTC。由于本地时间不存在,翻译引发异常。如果本地时间不明确,例如从夏令时设置回本地时钟时,也会引发异常(带有不同的错误消息)。
如果需要的话,库还提供了避免这些异常的语法。
这适用于VS-2013、VS-2015、clang和gcc。它需要C++11、C++14或C++1z。
上面的链接指向文档。这是github存储库:
https://github.com/HowardHinnant/date
time_t格式是一个整数值(自1970年1月1日00:00 UTC以来的秒数),因此time_t的所有可能值都存在(当然在使用的整数类型的限制范围内)。
另一方面,并非所有可能的"structtm"值(您有天、月、年、小时、分钟和秒的成员)都存在(这可能就是您的意思)。要检查"structtm"是否存在,您必须执行以下操作:
- 将成员tm_isdst设置为-1。这表示您不知道是否为夏令时。
- 使用mktime()将"structtm"转换为time_t
- 使用localtime()将time_t转换回"structtm"
- 将生成的"structtm"与初始的"struct tm"进行比较,忽略tm_isdst字段(或使用它来查看是否处于DST)