Pergunta

Este parece ser algo que ninguém nunca deveria ter que fazer, mas eu estou trabalhando em um módulo do kernel para um sistema embarcado (OpenWRT) em que parece que time.h não incluir o timespec e time_t tipos e as funções clock_gettime e gmtime, mas o não incluem localtime, ctime, time, ou, de forma crítica, o tipo tm.

Quando tento converter o ponteiro de retorno de gmtime a minha própria estrutura, eu recebo um segfault.

Então eu acho que eu seria o conteúdo para resolver o problema de duas maneiras-it'd ser ótimo para descobrir como obter acesso a esse tipo de falta, ou, alternativamente, como rolar o meu próprio método para decompor um unix timestamp.

Foi útil?

Solução

Isto deve ser precisa (preenche uma imitação cut-down de um struct tm, meu year usa Era Comum, em vez de uma época 1,900 CE):

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;
}

As minhas desculpas para todos os números mágicos. 367 * mês / 12 é um truque para gerar a sequência 30/31 dia do calendário. O cálculo trabalha com anos que começam em março até a correção no final, o que torna as coisas mais fáceis, porque então o dia salto cai no final de um "ano".

Outras dicas

Em glibc userspace vai fazer um monte de trabalho com relação a manusear a parte "local" da representação do tempo. Dentro do kernel este não estiver disponível. Provavelmente você não deve tentar se incomodar com isso dentro de seu módulo, se necessário fazê-lo no espaço do usuário.

A time_t é o número de segundos desde 1 de janeiro de 1970 UTC tão decomposição que em mês, dia, e ano que não é fornecido difícil que você deseja que o resultado no UTC. Há um monte de fonte disponível por Googling "fonte gmtime" . A maioria dos sistemas embarcados deixar de fora o processamento hora local, uma vez que é um pouco mais difícil devido à dependência de definição de fuso horário e para o ambiente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top