转换自"午夜1904-1-1"到日期时间字符串

时间:2018-04-09 11:01:54

标签: c++ c++11 time

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

据我所知,日期时间函数通常基于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://stackoverflow.com/a/49733937/3968307

3 个答案:

答案 0 :(得分:3)

这是使用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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

您可以使用系统中任何可用的电子表格应用程序轻松计算,这两个时间戳之间的差异(假设两者均为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