The time_t Value . . . and 16 Hours?

In last week’s Lesson, I covered the mechanics behind manually calculating a time_t value. My code was successful, but in a curious way.

Here is the full code:

2021_02_27-Lesson-a.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* calculate days in February
   from blog post https://c-for-dummies.com/blog/?p=3134
   this update returns the days of the month, not T/F
*/
int february(int year)
{
    /* if the year is divisible by both 100 and
       400, it's a leap year */
    if( (year%400)==0 )
        return(29);
    /* if the year is divisble by 100, it's not
       a leap year */
    if( (year%100)==0 )
        return(28);
    /* check for 4 year interval, which is redundant
       here, but I'll do it anyway */
    if( (year%4) != 0 )
        return(28);
    /* otherwise, it's a leap year */
    return(29);
}

/* Unix Epoch math */
time_t epoch(int year, int mon, int day)
{
    int days,y,m;
    int month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    /* calculate the number of days */
    days = 0;
    for( y=1970; y<year; y++ )
    {
        for( m=0; m<12; m++ )
        {
            if( m==1 )        /* february */
                days += february(y);
            else
                days += month[m];
        }
    }
    /* calculate final year, months only */
    for( m=0; m<mon-1; m++ )
    {
        if( m==1 )        /* february */
            days += february(y);        /* y value is proper */
        else
               days+=month[m];
    }
    /* add the day */
    days += day;
    /* tally up the seconds */
    return (time_t)(days * 24 * 60 * 60);
}

int main(int argc, char *argv[])
{
    int year, month, day;
    time_t now,my_now;
    struct tm *today;
    
    /* get current time */
    now = time(NULL);

    /* obtain invidiual values */
    today = localtime(&now);
    year = today->tm_year+1900;
    month = today->tm_mon+1;
    day = today->tm_mday;

    /* get calculated time_t value */
    my_now = epoch(year,month,day);

    /* output results */
    printf("For %4d %2d %2d:\n",year,month,day);
    printf("time_t value is:    %ld, %s",now,ctime(&now));
    printf("My time_t value is: %ld, %s",my_now,ctime(&my_now));

    return(0);
}

The main() function fills tm structure today with the current day’s time values. This part of the code is done for comparison purposes, but also to obtain the current year, month, and date. These values are passed to the epoch() function.

In the epoch() function, the code tallies the number of days for each month and cumulatively for each year until the current day. The february() function is called to ensure that days in leap years are properly counted.

The program’s output shows the time_t value for the current time as well as my manually calculated time_t value, which is off by 16 hours:

For 2021  2 13:
time_t value is:    1613238794, Sat Feb 13 09:53:14 2021
My time_t value is: 1613260800, Sat Feb 13 16:00:00 2021

In the output, the ctime() function shows the manually calculated time_t value as 16:00 and not midnight. I have no idea why. Tests run on all major platforms — Windows, Mac, and Linux — yielded the same result.

I believe the difference may have to do with my time zone, though I’m 8 hours behind UTF, not 16 hours ahead.

To test further, I wrote the following code:

2021_02_27-Lesson-b.c

#include <stdio.h>
#include <time.h>

int main()
{
    time_t epoch = 0;

    printf("Time: %s\n",ctime(&epoch));

    return(0);
}

This code quickly outputs the Unix Epoch value, which should be midnight January 1, 1970. But here’s the output:

Time: Wed Dec 31 16:00:00 1969

Uh.

Then it dawned on me. December 31, 1969 is indeed 8 hours behind UTF. My manual calculation is correct! But because I include the current day in my calculation, it’s one day ahead minus 8 hours for my locale’s time zone. Problem solved! Yet, the code must be updated with the locale calculation given the current time zone. I plumb this depth in next week’s Lesson.

Leave a Reply