【问题标题】:Convert the seconds since "midnight 1904-1-1" to a date-time string将自“午夜 1904-1-1”以来的秒数转换为日期时间字符串
【发布时间】:2026-02-09 11:45:01
【问题描述】:

在某些多媒体元数据中,可能有以秒为单位的日期时间 UTC 时间,1904 年 1 月 1 日午夜。

据我所知,日期时间函数通常基于 C/C++ 标准库中的 1970-1-1 午夜,至少在 Visual C++ 中,是否有 C/C++/Win32-API 中的函数来转换秒从“1904-1-1 午夜”到日期时间字符串,如“hh:mm:ss MM.dd, yyyy”或其他格式字符串或结构如“struct tm”?

struct tm
{
    int tm_sec;   // seconds after the minute - [0, 60] including leap second
    int tm_min;   // minutes after the hour - [0, 59]
    int tm_hour;  // hours since midnight - [0, 23]
    int tm_mday;  // day of the month - [1, 31]
    int tm_mon;   // months since January - [0, 11]
    int tm_year;  // years since 1900
    int tm_wday;  // days since Sunday - [0, 6]
    int tm_yday;  // days since January 1 - [0, 365]
    int tm_isdst; // daylight savings time flag
};

解决方案#1:

int main()
{
    SYSTEMTIME systm;
    memset(&systm, 0, sizeof(systm));

    systm.wYear = 1904;
    systm.wMonth = 1;
    systm.wDay = 1;

    FILETIME filetm;
    if (SystemTimeToFileTime(&systm, &filetm) == FALSE){
        printf("Failed to convert system time to file-time.\n");
        return 0;
    }

    ULARGE_INTEGER nanoSeconds;
    nanoSeconds.HighPart = filetm.dwHighDateTime;
    nanoSeconds.LowPart = filetm.dwLowDateTime;

    nanoSeconds.QuadPart += 3600ULL * 10000000; // add 1hour based on 1904/1/1 midnight

    filetm.dwHighDateTime = nanoSeconds.HighPart;
    filetm.dwLowDateTime = nanoSeconds.LowPart;

    if (FileTimeToSystemTime(&filetm, &systm) == FALSE){
        printf("Failed to convert file-time to system time.\n");
        return 0;
    }

    printf("New system time by adding 1 hour: %d-%02d-%02d %02d:%02d:%02d.%03d\n", 
        systm.wYear, systm.wMonth, systm.wDay, 
        systm.wHour, systm.wMinute, systm.wSecond, systm.wMilliseconds);

    return 0;
}

输出是

New system time by adding 1 hour: 1904-01-01 01:00:00.000

解决方案#2:

用@Howard Hinnant的date.h,也可以解决这个问题,请看他提供的示例代码https://*.com/a/49733937/3968307

【问题讨论】:

  • 不,C 或 C++ 库中没有这样的函数。但这似乎并不复杂。日期数学很久以前就已经解决了。我们可以很容易地计算出某一年有多少天,每天有多少秒,还有多少毫秒。基于此,这是一个相当简单的计算。我很确定(我希望)这类问题是每个中级计算机编程课程中的常规家庭作业。
  • 您可以使用 c++11 标准中的 std::chrono 在午夜 1904 年 1 月 1 日创建 time_point,然后添加秒数
  • 它需要有多好?例如,它是否需要处理闰秒?
  • Unix 时间戳已签名,因此 32 位值可追溯到 1901 年 12 月。另一方面,Win32 API 使用可追溯到 1601 的日期格式。请参阅 SYSTEMTIME and FILETIME
  • @KarstenKoop:unix 时代开始于 1970 年 1 月 1 日。并非所有系统都使用int32_t。在 64 位系统上,通常使用 int64_t

标签: c++ c++11 time


【解决方案1】:

现在是使用Howard Hinnant's free, open-source date/time library的好时机:

#include "date/date.h"
#include <cstdint>
#include <iostream>
#include <string>

std::string
convert(std::int64_t seconds_since_1904)
{
    using namespace date;
    using namespace std::chrono;
    constexpr auto offset = sys_days{January/1/1970} - sys_days{January/1/1904};
    return format("%T %m.%d, %Y", sys_seconds{seconds{seconds_since_1904}} - offset);
}

int
main()
{
    std::cout << convert(3'606'124'378) << '\n';
}

输出:

13:12:58 04.09, 2018

更新

以上代码将通过以下方式移植到 C++20(发货时):

  • #include "date/date.h" 更改为#include &lt;chrono&gt;
  • using namespace date; 更改为using namespace std;
  • "%T %m.%d, %Y" 更改为"{:%T %m.%d, %Y}"

【讨论】:

  • 我尝试运行你的示例代码,但是在我的环境中使用VS2015编译失败,错误信息如下:error C2127: 'date::nanyear': 'constexpr' entity的非法初始化带有非常量表达式
  • VS2015 在constexpr 上很弱。尝试使用 offset const 而不是 constexpr 的类型。它使该功能的效率降低了一些。我相信升级到 VS2017 会解决这个问题。
  • 啊,constexpr 偷偷溜进我的 date.h。感谢您的错误报告!我会马上解决的。同时,如果在 date.h 中将 constexpr year nanyear{-32768}; 更改为 CONSTDATA year nanyear{-32768};,它将在 VS2015 上运行。
  • 是的,把constexpr auto offset改成auto offset,把constexpr year nanyear{-32768}改成CONSTDATA year nanyear{-32768},VS2015就可以了!
  • 太棒了!我已经修复了 github 仓库。
【解决方案2】:

这里的时间问题实际上要求您为它编写自己的代码。 1900 年是一个例外,因为它可以被 4 整除,但仍然不是闰年,所以从 1904 年开始,您可以避免这种特殊例外,并利用从 1904 年开始每四年有 1461 天的事实。

【讨论】:

    【解决方案3】:

    您可以使用系统中的任何可用电子表格应用程序轻松计算,这两个时间戳之间的秒差(假设两者都是 UTC 时间)从 1/1/19041/1/1970 的秒差是 2,082,844,800 sec. 所以从 unix 时间戳 到您的时间的转换函数包括将 2082844800 添加到您从任何时间函数收到的 unix 时间戳。如果您想从时间中的时间戳传回 unix 时间戳,请从您的时间刻度中减去该固定值。请注意,该数字不适合 signed int,因此您可能必须使用 64 位数字来正确管理所有这些时间戳。如果您想使用纳秒级分辨率,情况会更糟。

    我不猜测使用那个奇怪的纪元时间戳的原因,但为了说明这种差异的实际和使用应用,互联网中有一个时间戳使用接近那个纪元,即 NTP(网络时间协议)时间戳,基于 1/1/1900 纪元,分辨率为 1/2**32 sec.,约为 232 ps.,有关此协议的规范,请参阅 RFC-5905

    【讨论】: