C ++ std :: string to time_t в UTC [дубликат]

Вот решение для шаблонов: Как обрабатывать круговые зависимости с шаблонами

Ключ к решению этой проблемы состоит в том, чтобы объявить оба класса до предоставления определений (реализаций). Невозможно разбить объявление и определение на отдельные файлы, но вы можете структурировать их так, как если бы они были в отдельных файлах.

6
задан Kit Fisto 10 September 2012 в 14:50
поделиться

3 ответа

Я решил реализовать свою собственную версию 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)) возвращает исходные входные значения. Поэтому я сравнил результаты для всех кратных 61 между 0 и MAX_INT для time_t, и они действительно равны (по крайней мере, в моей системе). Поэтому указанная выше процедура правильная.

Этот результат также означает, что библиотека C не учитывает секунды прыжка, что само по себе плохо, но полезно для моей цели. Обе функции будут оставаться неизменными в течение длительного времени. Чтобы быть абсолютно уверенным, мой класс Timestamp, который использует эту функцию, всегда выполняет быструю проверку запуска программы и доказывает согласованность для пары значимых значений.

8
ответ дан Kit Fisto 28 August 2018 в 16:30
поделиться

Для полноты, вот версия mkgmtime (), которая принимает struct tm * в качестве аргумента:

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;
}
7
ответ дан markgz 28 August 2018 в 16:30
поделиться

Как отмечено выше, в то время как time_t обычно представляет собой секунды, прошедшие с 1 января 1970 года, это нигде не указывается. Реализация, которая использует другое внутреннее представление, может отображаться в любое время, и любой код, который делает предположения о внутренней работе 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 до 4 февраля, а также ожидать, что 9:50 DST в середине зимы станут стандартным временем 8:50.)

Он страдает от одной потенциальной ошибки: если смещение UTC часового пояса изменяется по причинам, не отраженным в знаке DST, временные метки вокруг времени перехода могут быть истолкованы неправильно: стандартный случай - это когда законодательство изменяет свой часовой пояс (например, Литва после советских времен, после независимости, изменился с советского времени, а через несколько лет - на EET). В середине лета некоторые законодательные акты имели двойной DST, ездя через 3 разных смещения UTC в год, которые флаг DST не может представлять.

0
ответ дан user149408 28 August 2018 в 16:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: