如何转换UTC日期和时间,在C ++中的time_t?(How to convert a UTC d

2019-06-28 02:51发布

我想转换成数字给出的年,月,日,等来一个time_t的一个UTC日期和时间。 有些系统提供了类似功能mkgmtimetimegm用于此目的,但不是标准,我的Solaris系统上不存在。

我发现的唯一解决办法,到目前为止涉及到本地时区设置与UTC SETENV,然后调用mktime 。 但是这种方法不是线程安全的,速度慢,不便于携带,甚至产生我的系统上的内存泄漏。

我也看到,试图确定当前UTC方法采用偏移gmtime ,然后补充说,到的结果mktime 。 但据我所看到的所有这些方法有差距。 毕竟,从本地时间UTC的转换不是唯一的。

你认为什么是最好的解决办法?

Answer 1:

我决定实现自己的mkgmtime的版本,它比我想象的更容易。

const int SecondsPerMinute = 60;
const int SecondsPerHour = 3600;
const int SecondsPerDay = 86400;
const int DaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool IsLeapYear(short year)
{
    if (year % 4 != 0) return false;
    if (year % 100 != 0) return true;
    return (year % 400) == 0;
}

time_t mkgmtime(short year, short month, short day, short hour, short minute, short second)
{
    time_t secs = 0;
    for (short y = 1970; y < year; ++y)
        secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay;
    for (short m = 1; m < month; ++m) {
        secs += DaysOfMonth[m - 1] * SecondsPerDay;
        if (m == 2 && IsLeapYear(year)) secs += SecondsPerDay;
    }
    secs += (day - 1) * SecondsPerDay;
    secs += hour * SecondsPerHour;
    secs += minute * SecondsPerMinute;
    secs += second;
    return secs;
}

我主要担心的是, mkgmtime必须一致gmtime 。 使得gmtime(mktime(t))返回原始输入值。 因此,我比较了0和MAX_INT之间的time_t的61倍数的结果,他们确实是平等的(至少在我的系统)。 因此,根据上述程序是正确的。

这一结果也意味着,C库没有考虑闰秒考虑,这本身就是对我的目的是件坏事,但良好。 这两个功能将保持很长一段时间保持一致。 要绝对肯定的是,使用这个功能我戳类始终在执行程序开始进行快速检查,并证明了几个有意义的值的一致性。



Answer 2:

为了完整起见,这里,需要一个结构TM *作为参数mkgmtime()的一个版本:

static time_t mkgmtime(const struct tm *ptm) {
    time_t secs = 0;
    // tm_year is years since 1900
    int year = ptm->tm_year + 1900;
    for (int y = 1970; y < year; ++y) {
        secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay;
    }
    // tm_mon is month from 0..11
    for (int m = 0; m < ptm->tm_mon; ++m) {
        secs += DaysOfMonth[m] * SecondsPerDay;
        if (m == 1 && IsLeapYear(year)) secs += SecondsPerDay;
    }
    secs += (ptm->tm_mday - 1) * SecondsPerDay;
    secs += ptm->tm_hour       * SecondsPerHour;
    secs += ptm->tm_min        * SecondsPerMinute;
    secs += ptm->tm_sec;
    return secs;
}


Answer 3:

如上所述,而time_t通常表示自1970年1月1日起经过秒,这不是在任何地方指定。 它采用了不同的内部表示可能出现的任何时间执行,这使得有关的内部运作假设的任何代码time_t将无法正常工作在那里。

一番考虑后,我想出了以下内容:

time_t mkgmtime(struct tm * pt) {
    time_t ret;

    /* GMT and local time */
    struct tm * pgt, * plt;

    ret = mktime(pt);

    pgt = g_memdup(gmtime(ret), sizeof(struct tm));
    plt = g_memdup(localtime(ret), sizeof(struct tm));

    plt->tm_year -= pgt->tm_year - plt->tm_year;
    plt->tm_mon -= pgt->tm_mon - plt->tm_mon;
    plt->tm_mday -= pgt->tm_mday - plt->tm_mday;
    plt->tm_hour -= pgt->tm_hour - plt->tm_hour;
    plt->tm_min -= pgt->tm_min - plt->tm_min;
    plt->tm_sec -= pgt->tm_sec - plt->tm_sec;

    ret = mktime(plt);

    g_free(pgt);
    g_free(plt);

    return ret;
}

有人可能会进一步下探可能优化该plt (使用pt在其位,并省略localtime()g_free(plt)调用)。

这应该跨越其暴露的所有实现工作mktime() gmtime()localtime()包括跨DST转换日期。 ( mktime()将“正常化”超出范围的值,例如转弯月35到2月4日;我也期望在冬天变成8:50标准时间的中间9:50 DST)。

它从一个潜在的bug受苦:如果一个时区的UTC偏移不反映在DST标志原因的变化,周围的割接时间时间戳可能会错误地解释:标准的情况是,当一个立法改变其时区(例如,立陶宛从改变苏联时期独立后CET,后来到EET几年)。 一些立法在盛夏有双DST,每年通过3点不同的UTC偏移,其中DST标志不能代表骑自行车。



文章来源: How to convert a UTC date & time to a time_t in C++?
标签: c++ time-t