Domanda

Questo mi sembra qualcosa che nessuno dovrebbe mai avere a che fare, ma sto lavorando su un modulo del kernel per un sistema embedded (OpenWRT), in cui sembra che time.h fa includono la timespec e time_t tipi e le funzioni clock_gettime e gmtime, ma lo fa non includere localtime, ctime, time, o, in modo critico, il tipo tm.

Quando tento di lanciare il puntatore di ritorno da gmtime al mio struct, ottengo un segmentation fault.

Quindi credo che sarei contento di risolvere il problema due modi-it'd essere grande per capire come ottenere l'accesso a quel tipo mancante, o, in alternativa, come rotolare il mio metodo per la decomposizione di un unix timestamp.

È stato utile?

Soluzione

Questo dovrebbe essere precisi (compila un imitazione cut-down di un struct tm, il mio year utilizza Common Era al posto di un'epoca 1900 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;
}

Le mie scuse per tutti i numeri di magia. 367 * al mese / 12 è un trucco per generare la sequenza 30/31 giorno del calendario. Il calcolo funziona con gli anni che iniziano di marzo fino alla correzione, alla fine, il che rende le cose facili perchè poi il giorno salto cade alla fine di un "anno".

Altri suggerimenti

In userspace glibc farà un sacco di lavoro per quanto riguarda la gestione della parte "locale" della rappresentazione tempo. All'interno del kernel questo non è disponibile. Probabilmente non si dovrebbe cercare di preoccuparsi di questo all'interno del modulo, se necessario, farlo in userspace.

Una time_t è il numero di secondi dal 1 Gennaio 1970 UTC in modo che in decomposizione in mese, il giorno e l'anno non è così difficile a patto che si desidera che il risultato in UTC. C'è un di sorgente disponibile da usare Google "fonte gmtime". La maggior parte dei sistemi integrati di elaborazione lasciano fuori ora locale dal momento che è un po 'più difficile a causa della dipendenza da impostazione del fuso orario e per l'ambiente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top