我试图使用std::chrono::time_point<std::chrono::system_clock>
将当前年份存储在1970年以前的某个日期,但是我遇到了从其内容读取到{{1}的问题结构。
我先将std::tm
转换为time_point
,之后我会读取其值以获取time_t
值。但是,在尝试执行此操作时,代码在使用tm_year
时失败,但在我使用localtime_s
时成功。这仅适用于1-1-1970之前的日期,使用这两种功能的日期之后的日期。
以下代码重现错误。如果使用gmtime_s
调用terstGmTimeVsLocalTime
,则可以使用utc=true
,如果使用utc=false
调用它,则无法生成正确的输出。
#include <iomanip>
#include <time.h>
#include <iostream>
void testGmTimeVsLocaltime(const bool& utc) {
// Create time
std::tm timeInfoWrite = std::tm();
timeInfoWrite.tm_year = 1969 - 1900; // Year to parse, here it is 1969
timeInfoWrite.tm_mon = 0;
timeInfoWrite.tm_mday = 1;
timeInfoWrite.tm_hour = 1;
timeInfoWrite.tm_min = 0;
timeInfoWrite.tm_sec = 0;
timeInfoWrite.tm_isdst = -1;
std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::from_time_t(utc ? _mkgmtime(&timeInfoWrite) : std::mktime(&timeInfoWrite));
// Convert to time_t
std::time_t timeT = std::chrono::system_clock::to_time_t(timePoint);
// Read values
std::tm timeInfoRead;
if (utc) {
gmtime_s(&timeInfoRead, &timeT);
} else {
localtime_s(&timeInfoRead, &timeT);
}
// Output result
std::cout << (timeInfoRead.tm_year + 1900) << '\n';
// Wait for input
std::getchar();
}
int main() {
testGmTimeVsLocaltime(true); // Set to false to show bug
return 0;
}
正如预期的那样, utc=true
输出1969年。但是,utc=false
输出1899(可能是因为发生错误而tm_year
设置为-1)。
我有什么遗失的吗? The documentation并未明确指定{1}}在1-1-1970之前的日期失败。
我在Windows 10 x64上如果它有所作为。
答案 0 :(得分:1)
使用Howard Hinnant's free, open-source date lib,您可以完全支持笨拙,错误和容易出错的C api,并直接使用基于<chrono>
的现代系统:
#include "chrono_io.h"
#include "date.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
sys_days timePoint = timeInfoWrite; // this is a chrono::time_point
std::cout << timePoint.time_since_epoch() << '\n'; // -365 days
// Convert to time_t
// no need
// Read values
year_month_day timeInfoRead = timePoint;
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
输出:
-365[86400]s
1969
有一些文字可以很容易地填写一个year_month_day
结构,它类似于tm
的年,月和日部分。您可以轻松将其转换为std::chrono::time_point<system_clock, days>
(sys_days
)。这与system_clock::time_point
相同,但精确度为天。它本身将隐式转换为秒精度time_point
(typedef&#39; d到sys_seconds
)或system_clock::time_point
。
上面我只输出time_since_epoch()
,表明它是在纪元前的-365天。
从来没有真正需要转换为C API数据结构,但如果您愿意,这很容易。例如,假设time_t
是1970-01-01以来的秒数:
std::time_t timeT = sys_seconds{timePoint}.time_since_epoch().count();
std::cout << timeT << '\n';
输出:
-31536000
反向转换(回到year_month_day
)同样容易。如果您想从timeT
进行转换,则只需稍微参与其中:
year_month_day timeInfoRead = floor<days>(sys_seconds{seconds{timeT}});
首先将time_t
转换为chrono::seconds
,然后转换为seconds
- precsion time_point
,然后转换为days
- precsion {{1} },最后到time_point
字段类型(year_month_day
- 就像)。
最后tm
有一个year_month_day
getter成员函数,可以流式传输。如果需要,您可以明确地将year()
转换为year
:
int
但我认为最好将年,月和日等事物保存为不同的类型,这样编译器可以帮助您在意外混淆时捕获它们。
最后,如果您真的想要在计算机的本地时区中使用1969-01-01 00:00:00,there's a library也可以这样做。它只是对上述简单程序的一个小修改。
int{timeInfoRead.year()}
输出:
#include "tz.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
using namespace std::chrono;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
auto timePoint = make_zoned(current_zone(), local_days{timeInfoWrite});
// Convert to time_t
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
std::cout << timeT << '\n';
// Read values
timePoint = sys_seconds{seconds{timeT}};
year_month_day timeInfoRead{floor<days>(timePoint.get_local_time())};
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
现在,您使用计算机的-31518000
1969
时区创建zoned_seconds
,并将current_zone()
转换为timeInfoWrite
而不是local_days
。< / p>
您可以从sys_days
获取当地时间或系统时间。要转换为timePoint
,系统时间最有意义:
time_t
现在输出(对我来说)是5小时后(18000年代)。
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
您可以使用-31518000
或.get_local_time()
返回本地年份或系统(UTC)年份。对我来说没有区别(.get_sys_time()
)。但是,如果您在"America/New_York"
,如果您申请UTC年而不是1969年,那么您将获得1968年。通过简单地替换"Australia/Sydney"
,这一切都很容易模拟或上述计划中的"Australia/Sydney"
"America/New_York"
。
是的,它适用于Windows,VS-2013及更高版本。时区lib需要一些安装:https://howardhinnant.github.io/date/tz.html#Installation