Вопрос

Кажется, что никому никогда не придется этого делать, но я работаю над модулем ядра для встраиваемой системы (OpenWRT), в котором кажется, что time.h делает включить timespec и time_t типы и clock_gettime и gmtime функционирует, но делает нет включать localtime, ctime, time, или, что особенно важно, tm тип.

Когда я пытаюсь привести указатель возврата из gmtime в свою собственную структуру, я получаю ошибку segfault.

Поэтому я думаю, что был бы доволен решением проблемы любым из двух способов: было бы здорово выяснить, как получить доступ к этому отсутствующему типу, или, альтернативно, как реализовать свой собственный метод для декомпозиции временной метки Unix.

Это было полезно?

Решение

Это должно быть точно (заполняет урезанную имитацию struct tm, мой year использует нашу эпоху вместо эпохи 1900 года нашей эры):

struct xtm
{
    unsigned int year, mon, day, hour, min, sec;
};

#define YEAR_TO_DAYS(y) ((y)*365 + (y)/4 - (y)/100 + (y)/400)

void untime(unsigned long unixtime, struct xtm *tm)
{
    /* First take out the hour/minutes/seconds - this part is easy. */

    tm->sec = unixtime % 60;
    unixtime /= 60;

    tm->min = unixtime % 60;
    unixtime /= 60;

    tm->hour = unixtime % 24;
    unixtime /= 24;

    /* unixtime is now days since 01/01/1970 UTC
     * Rebaseline to the Common Era */

    unixtime += 719499;

    /* Roll forward looking for the year.  This could be done more efficiently
     * but this will do.  We have to start at 1969 because the year we calculate here
     * runs from March - so January and February 1970 will come out as 1969 here.
     */
    for (tm->year = 1969; unixtime > YEAR_TO_DAYS(tm->year + 1) + 30; tm->year++)
        ;

    /* OK we have our "year", so subtract off the days accounted for by full years. */
    unixtime -= YEAR_TO_DAYS(tm->year);

    /* unixtime is now number of days we are into the year (remembering that March 1
     * is the first day of the "year" still). */

    /* Roll forward looking for the month.  1 = March through to 12 = February. */
    for (tm->mon = 1; tm->mon < 12 && unixtime > 367*(tm->mon+1)/12; tm->mon++)
        ;

    /* Subtract off the days accounted for by full months */
    unixtime -= 367*tm->mon/12;

    /* unixtime is now number of days we are into the month */

    /* Adjust the month/year so that 1 = January, and years start where we
     * usually expect them to. */
    tm->mon += 2;
    if (tm->mon > 12)
    {
        tm->mon -= 12;
        tm->year++;
    }

    tm->day = unixtime;
}

Мои извинения за все эти магические числа.367*месяц/12 — это изящный трюк для создания последовательности дней календаря 30/31.Расчет работает с годами, которые начинаются в марте, до исправления в конце, что упрощает задачу, потому что тогда високосный день выпадает на конец «года».

Другие советы

В пользовательском пространстве glibc проделает большую работу по обработке «локальной» части представления времени.В ядре это недоступно.Вероятно, вам не следует заморачиваться с этим внутри вашего модуля, если необходимо, сделайте это в пользовательском пространстве.

А time_t — это количество секунд с 1 января 1970 года по всемирному координированному времени, поэтому разложить его на месяц, день и год не так уж сложно, если вам нужен результат в формате UTC.Eсть доступна куча исходников по Гуглу "источник gmtime".Большинство встроенных систем не учитывают обработку местного времени, поскольку это немного сложнее из-за зависимости от настроек часового пояса и окружающей среды.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top