gmtime()函数是否考虑了闰年?

时间:2017-03-22 22:45:18

标签: c++ datetime embedded-linux microcontroller epoch

我正在使用嵌入式Linux,系统/控制器时间自1970年1月1日起以毫秒的​​形式保存。我正在尝试使用gmtime,但无法获得准确的结果。将此时间(毫秒)转换为实时小时的任何示例:分钟:秒:天:月将会有所帮助。

2 个答案:

答案 0 :(得分:1)

gmtime()不仅支持闰年,还支持闰秒,这就是定义tm_sec字段范围的原因如[0..60]包含。

答案 1 :(得分:1)

你可以使用civil_from_days,它是在Howard Hinnant的chrono-Compatible Low-Level Date Algorithms中得到并详细解释的。此函数需要自1970年1月1日以来的天数并将其转换为{y, m, d}字段。完成后,您只需要处理从毫秒时间戳减去自午夜以来的毫秒数的天数,然后将其分解为h:M:s.ms

这是完整的代码:

#include <iostream>
#include <iomanip>
#include <cstdint>

int
main()
{
    using namespace std;
    int64_t t = 1490285505123;       // milliseconds since epoch
    int32_t z = (t >= 0 ? t : t - (1000*86400-1))/(1000*86400); // days since epoch
    t -= z * (1000LL * 86400);       // milliseconds since midnight
    z += 719468;
    int32_t era = (z >= 0 ? z : z - 146096) / 146097;
    int32_t doe = z - era * 146097;
    int32_t yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;
    int32_t y = yoe + era * 400;
    int32_t doy = doe - (365*yoe + yoe/4 - yoe/100);
    int32_t m = (5*doy + 2)/153;
    int32_t d = doy - (153*m + 2)/5 + 1;  // day
    m += m < 10 ? 3 : -9;                 // month
    y += m <= 2;                          // year
    int32_t h = t / (1000 * 3600);        // hour
    t -= h * (1000 * 3600);
    int32_t M = t / (1000 * 60);          // minute
    t -= M * (1000 * 60);
    int32_t s = t / 1000;                 // second
    int32_t ms = t - s * 1000;            // ms
    cout.fill('0');
    cout << setw(4) << y << '-' << setw(2) << m << '-' << setw(2) << d
                    << ' ' << setw(2) << h << ':' << setw(2) << M
                    << ':' << setw(2) << s << '.' << setw(3) << ms << '\n';
}

就像我用作输入1490285505123ms的一个例子,输出是:

2017-03-23 16:11:45.123

这需要考虑闰年。它不需要考虑闰秒。您的嵌入式Linux系统/控制器也不太可能,因此尝试这样做是不正确的。

上述算法对t具有非常大的有效范围:

-5877641-06-23 00:00:00.000 <= t <= 5880010-09-09 23:59:59.999

(+/- 580万年)

如果您不介意将t的下限限制为0000-03-01 00:00:00.000,那么您可以将era的计算简化为:

int32_t era = z / 146097;

如果您可以将t的下限限制为1970-01-01 00:00:00.000,那么z的计算可以简化为:

int32_t z = t / (1000 * 86400);  // days since epoch

最后,如果你愿意将t限制在这400年的范围内:

2000-03-01 00:00:00.000 <= t <= 2400-02-29 23:59:59.999

然后era可以变得简单:

int32_t const era = 5;

Fwiw,这里是high-level date/time library利用C ++ 11/14 <chrono>库完成相同的计算,只需要更清晰的语法。你的std :: lib必须支持<chrono>才能使用这个库:

#include "date.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;
    cout << sys_time<milliseconds>(1490285505123ms) << '\n';
}