C++ 本地时间失败,gmtime成功,日期在1970年1月1日之前

C++ 本地时间失败,gmtime成功,日期在1970年1月1日之前,c++,chrono,time-t,C++,Chrono,Time T,我试图使用std::chrono::time_point将当前年份存储在1970年之前的日期中,但是我遇到了一个问题,即如何将其内容读取到std::tm结构中 我首先将time\u点转换为time\u t,然后读取其值以获得tm\u年值。但是,当尝试这样做时,使用localtime\u s时代码失败,而使用gmtime\u s时代码成功。这仅适用于1970年1月1日之前的日期,之后的日期可以使用这两个函数 下面的代码再现了错误。如果使用utc=true调用terstGmTimeVsLocalTi

我试图使用
std::chrono::time_point
将当前年份存储在1970年之前的日期中,但是我遇到了一个问题,即如何将其内容读取到
std::tm
结构中

我首先将
time\u点
转换为
time\u t
,然后读取其值以获得
tm\u年
值。但是,当尝试这样做时,使用
localtime\u s
时代码失败,而使用
gmtime\u s
时代码成功。这仅适用于1970年1月1日之前的日期,之后的日期可以使用这两个函数

下面的代码再现了错误。如果使用
utc=true
调用
terstGmTimeVsLocalTime
,它会工作,如果使用
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;
}
#包括
#包括
#包括
void testGmTimeVsLocaltime(常量布尔和utc){
//创造时间
std::tm timeInfoWrite=std::tm();
timeInfoWrite.tm_year=1969-1900;//解析年份,这里是1969年
timeInfoWrite.tm_mon=0;
timeInfoWrite.tmmday=1;
timeInfoWrite.tm_hour=1;
timeInfoWrite.tm_min=0;
timeInfoWrite.tm_sec=0;
timeInfoWrite.tm_isdst=-1;
std::chrono::time_point timePoint=std::chrono::system_clock::from_time_t(utc?_mkgmtime(&timeInfoWrite):std::mktime(&timeInfoWrite));
//转换为时间
std::time\u t timeT=std::chrono::system\u clock::to\u time\u t(时间点);
//读取值
std::tm timeInfoRead;
如果(utc){
gmtime_s(&TIMEInfread,&timeT);
}否则{
本地时间(timeInfoRead和timeT);
}
//输出结果
std::cout使用,您可以完全避开笨拙、易出错和易出错的C api,直接使用基于现代
的系统:

#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();
}
有文字可以方便地填写
year\u month\u day
结构,该结构类似于
tm
的年、月和日部分。您可以轻松地将其转换为
std::chrono::time\u point
sys\u days
)。这与
系统时钟::时间点
相同,但精度为天。它本身将隐式转换为秒精度
时间点
(键入定义为
系统秒
),或转换为
系统时钟::时间点

上面我只输出了它的
时间\u自\u epoch()
,这表明它比epoch早-365天

实际上根本不需要转换为C API数据结构,但如果您愿意,这很容易。例如,假设自1970-01-01以来
time\u t
为秒:

std::time_t timeT = sys_seconds{timePoint}.time_since_epoch().count();
std::cout << timeT << '\n';
反向转换(返回到
year\u month\u day
)也同样简单。如果您想从
timeT
转换,只需要稍微多做一点:

year_month_day timeInfoRead = floor<days>(sys_seconds{seconds{timeT}});
但我认为最好将年、月和日作为不同的类型保存,这样编译器可以帮助您在不小心将它们混淆时捕获它们

最后,如果你真的想把1969-01-01 00:00:00放在你电脑的本地时区,也可以这样做。这只是对上面简单程序的一个小小修改

#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();
}
现在,您可以使用计算机的
当前时区()
创建一个
分区的\u秒
,并将
timeInfoWrite
转换为
本地\u天
,而不是
系统\u天

您可以从
时间点
中获取本地时间或系统时间。要转换为
时间
,系统时间最有意义:

std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
现在输出(对我来说)是5小时后(18000)

您可以使用
.get\u local\u time()
.get\u sys\u time()
返回本地年份或系统(UTC)年份。对我来说,这没有什么区别(
“美国/纽约”
)。但是如果您在
“澳大利亚/悉尼”
,如果您申请UTC年而不是1969年,您将获得1968年。在上面的程序中,只需将
当前区域()
替换为
“澳大利亚/悉尼”
“美国/纽约”
,即可轻松模拟

#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();
}

是的,它可以在Windows、VS-2013和更高版本上运行。时区库需要一些安装:

MSDN文档建议它将失败:“1970年1月1日午夜之前。”看@RichardCritten啊,我知道我一定是使用了一个特定于操作系统的实现。没有意识到
localtime\u s
不是标准的一部分。1970年1月1日午夜之前,是否还有另一个函数不会因值而失败?或者可能是另一种策略?我想我可以检索UTC和localtime之间的差异,simpl可以使用
gmtime\s
函数,然后在需要本地时间时将差异添加到结果中,但这似乎可以更简单。您链接的文档称为“从历元开始转换给定时间”;其中epoch是实现决定时间开始的时间。在Windows上,有操作系统调用可以在任何时间工作,但我不知道有任何标准API。
#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
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
-31518000