std::tm 到 std::time_t 转换给出 1970 年之前特定日期的错误 (c++)

std::tm to std::time_t conversion gives error for a specific date before 1970 (c++)

我目前正在尝试通过 time_t 存储出生日期。为此,我还使用了 std::mktimestd::tm。但是,当我尝试将特定日期从 std::tm 转换为 std::time_t 时,它 returns -1,这表明转换不成功。我知道 Unix 时间戳应该存储从 1970 年 1 月 1 日 UTC 开始的秒数,但我找不到任何表明不允许使用负时间戳的参考。 为什么会这样?我应该使用其他替代方法来存储出生日期吗?

#include <ctime>
#include <iostream>

int main(int argc, char const *argv[])
{
    int year = 1914;
    int month = 1;
    int day = 1;

    std::tm tm{};
    std::time_t timestamp;
    tm.tm_year = year - 1900;
    tm.tm_mon = month - 1;
    tm.tm_mday = day;
    timestamp = std::mktime(&tm);

    std::cout << timestamp << std::endl;
    return 0;
}

如果您有兴趣使用 date1 库将日期存储为天数,它看起来像这样:

#include "date/date.h"
#include <cassert>
#include <chrono>
#include <iostream>

int
main()
{
    namespace chr = date;
//  namespace chr = std::chrono;

    int year = 1914;
    int month = 1;
    int day = 1;

    chr::sys_days timestamp = chr::year{year}/month/day;
    int intstamp = timestamp.time_since_epoch()/chr::days{1};

    std::cout << intstamp << '\n';

    chr::year_month_day recover_birthday = chr::sys_days{chr::days{intstamp}};
    assert(year  ==      int{recover_birthday.year()});
    assert(month == unsigned{recover_birthday.month()});
    assert(day   == unsigned{recover_birthday.day()});

    std::cout << "min date = "  << chr::year::min()/01/01 << '\n';
    std::cout << "max date =  " << chr::year::max()/12/31 << '\n';
}

输出:

-20454
min date = -32767-01-01
max date =  32767-12-31

上面我展示了两种方式的转换:

  1. {year, month, day}int
  2. int{year, month, day}

我还为 {year, month, day} 数据结构添加了 self-documenting 有效范围。

这将适用于 C++11/14/17。 date1 是一个 open-source 免费的 header-only 库,无需安装。就 #include "date/date.h"。如果您需要时区支持(本例不需要),那么在 link.

上还有一个非 header-only 库

如果您不想使用 date1,它包装的用于执行此计算的算法记录在 此处

date1 库也是 C++20 <chrono> 的预览版。要将上述程序移植到 C++20,请删除 #include "date/date.h" 并将 namespace chr = date; 更改为 namespace chr = std::chrono;.


1 完全披露:我是这个库的主要作者。我不会从这项工作中寻求任何经济利益。但有时如果我不完全公开这些信息,人们会变得脾气暴躁。