How to split unix time in C

It seems that no one should ever do, but I'm working on the kernel module for embedded system (OpenWRT), in which it seems that time.hincludes the types timespecand time_t, and clock_gettime, and gmtime, but does not include localtime, ctime, timeand, critically, the type tm.

When I try to drop the return pointer from gmtime into my own structure, I get segfault.

So, I think I would be happy with the solution to the problem in two ways - it would be great to find out how to access this missing type, or, alternatively, how to collapse your own method for decomposing a unix timestamp.

+3
source share
3 answers

This should be accurate (fills the abbreviated simulation struct tm, mine yearuses Common Era instead of the 1900 era):

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

I apologize for all the magic numbers. 367 * month / 12 is a neat trick to generate a 30/31 day calendar sequence. The calculation works with the years that begin in March before fixing at the end, which facilitates the process, because then the leap day falls at the end of the "year".

+5
source

In user space, glibc will do a great job of processing the "local" part of the time view. This is not available inside the kernel. You should probably not try to worry about this in your module if you need to do this in user space.

0

A time_tis the number of seconds since January 1, 1970 UTC, so decomposing into a month, day and year is not so difficult if you want to get the result in UTC. There is a bunch of source available from Googling "gmtime source" . Most embedded systems do not take local time processing into account, as it is a bit more complicated due to the time zone setting and the environment.

0
source

All Articles