gpt4 book ai didi

c++ - localtime_s 失败,而 gmtime_s 在 1-1-1970 之前的日期成功

转载 作者:行者123 更新时间:2023-11-28 05:17:38 28 4
gpt4 key购买 nike

我正在尝试使用 std::chrono::time_point<std::chrono::system_clock> 将当前年份存储在 1970 年之前的日期中,但是我遇到了一个关于从其内容读取到 std::tm 的问题结构。

我转换 time_pointtime_t首先,然后我读取它的值以获得 tm_year值(value)。但是,当尝试这样做时,代码在使用 localtime_s 时失败了。 , 但是当我使用 gmtime_s 时它成功了.这仅适用于 1-1-1970 之前的日期,之后的日期可以很好地使用这两个函数。

下面的代码重现了错误。如果terstGmTimeVsLocalTimeutc=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没有具体说明 localtime_s对于 1-1-1970 之前的日期应该会失败。

如果它有所作为,我正在使用 Windows 10 x64。

最佳答案

使用 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 struct 类似于 tm 的年月日部分.您可以轻松地将其转换为 std::chrono::time_point<system_clock, days> (sys_days)。这与 system_clock::time_point 相同, 但精度为天。它本身将隐式转换为秒精度 time_point (类型定义为 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_tchrono::seconds , 然后到 seconds -精度time_point , 然后到 days -精度time_point , 最后到 year_month_day字段类型( tm -like)。

最后year_month_day有一个 year()可流式传输的 getter 成员函数。您可以显式转换 yearint如果需要:

int{timeInfoRead.year()}

但我认为最好将年、月和日之类的东西保持为不同的类型,以便编译器可以帮助您在不小心混淆它们时发现它们。

最后,如果您真的想要计算机本地时区中的 1969-01-01 00:00:00,there's a library也这样做。并且它只是对上面简单程序的一个小修改。

#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()时区,并转换您的 timeInfoWritelocal_days而不是 sys_days .

您可以从timePoint 中获取本地时间或系统时间.用于转换为 time_t ,系统时间最有意义:

std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();

现在(对我而言)输出是 5 小时后(18000 秒)。

-31518000

您可以使用 .get_local_time() 取回本地年份或系统 (UTC) 年份或 .get_sys_time() .对我来说这没有区别( "America/New_York" )。但如果你在 "Australia/Sydney" ,如果您请求 UTC 年份而不是 1969,您将得到 1968。这一切都非常容易通过简单地替换 "Australia/Sydney" 来模拟。或 "America/New_York"对于 current_zone()在上面的程序中。

是的,它适用于 Windows、VS-2013 及更高版本。时区库需要一些安装:https://howardhinnant.github.io/date/tz.html#Installation

关于c++ - localtime_s 失败,而 gmtime_s 在 1-1-1970 之前的日期成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42286616/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com