Parsing Integer Values Into a time_t Value

Pulling a date from a string involves slicing the string into substrings, which are then converted into values for year, month, and day. Last week’s Lesson demonstrated such code. This week, the final step is accomplished, converting year, month, and day integers into a time_t value.

I can think of two ways to create a time_t value. My default method, which I’ve written about before on this blog, is to populate a tm structure which can then be converted into a time_t value. It’s kind of a backwards way to obtain the value, but I know it works.

As a review, the time_t value represents the Unix epoch, or the number of seconds passed since January 1, 1970. The tm structure contains members that reference individual parts of a date, such as the year, month, day of the month, and so on. Both of time_t and the tm structure are defined in the time.h header file.

In my earlier post, I populated a tm structure with the current time, then updated specific members to reflect the time_t value I wanted. Here’s a snippet from the code:

time(&today);
birthday = localtime(&today);
birthday->tm_mon = month-1;
birthday->tm_mday = day;
birthday->tm_year = year-1900;

bday = mktime(birthday);

The time() function sets the current time’s time_t value into variable today.

The localtime() function extracts from the time_t value individual members of the tm structure birthday.

The month, day, and year members of tm structure birthday are updated with values from int variables month, day, and year.

Finally, the mktime() function converts the data from tm structure birthday into the time_t value bday.

I wondered if you really need to pre-populate a tm structure to make this process work? So I ran a test and filled various members of the structure directly. Alas, the results were inconsistent, so I retained my approach from the earlier blog post.

Here’s the final version of the filename-to-time_t code:

2021_02_13-Lesson.c

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

/* copy and convert the digits */
char *convert( char *s, int size )
{
    int x;
    static char buffer[5];
    char c;

    for( x=0; x<size; x++ )
    {
        c = *(s+x);
        if( c=='.' || c=='\0' )
        {
            fprintf(stderr,"Malformed filename\n");
            exit(2);
        }
        buffer[x] = c;
    }
    buffer[x] = '\0';

    return(buffer);
}

int main(int argc, char *argv[])
{
    char *filename;
    int year, month, day;
    time_t now,file;
    struct tm *date;
    
    /* check for filename argument */
    if( argc<2 )
    {
        /* output error message to standard error */
        fprintf(stderr,"Filename option required\n\n");
        /* leave with exit code 1*/
        exit(1);
    }
    /* assign to pointer for convenience */
    filename = argv[1];

    /* code to confirm that the file exists goes here */
    /* ... */
    
    /* extract integers. */
    year = strtol(convert(filename+0,4),NULL,10);
    month = strtol(convert(filename+4,2),NULL,10);
    day = strtol(convert(filename+6,2),NULL,10);

    /* fill the tm structure with the current date/time */
    time(&now);
    date = localtime(&now);
    /* backfill some specific items in the date structure */
    date->tm_sec = 0;
    date->tm_min = 0;
    date->tm_hour = 0;
    date->tm_mday = day;
    date->tm_mon = month - 1;
    date->tm_year = year - 1900;
    /* convert the structure to a time_t value */
    file = mktime(date);

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

    return(0);
}

Line 54 generates a time_t value in variable now. The tm structure date is filled at Line 55.

From Lines 57 through 62, the tm structure date is updated with new values. The month and year values must be modified to fit into the tm structure properly; months are numbered from zero and years start at 1900.

Sample output for the argument 20210115.txt:

2021  1 15
time_t value is 1610697600
Fri Jan 15 00:00:00 2021

And for 2021okay.txt

2021  0  0
time_t value is 1606723200
Mon Nov 30 00:00:00 2020

With the output above, you see that bogus data is generated due to the bogus input. The code doesn’t validate input to the degree necessary to detect this issue. I leave a solution up to you.

In next week’s Lesson, I cover how to manually create a time_t value.

2 thoughts on “Parsing Integer Values Into a time_t Value

  1. “I wondered if you really need to pre-populate a tm structure to make this process work? So I ran a test and filled various members of the structure directly. Alas, the results were inconsistent, so I retained my approach from the earlier blog post.”

    Not sure if this is relevant to your problem but I’ll paste in something I wrote in an article on the subject which I hope will help:

    “The mktime function also adjusts any values which exceed their maximum. For example if you create a tm struct with a date of 31 June then mktime will change it to 1 July. For this reason it is important to set all six date/time members even if you aren’t interested in them. If you do not they will contain garbage values which mktime will use to adjust the members which you did set.”

Leave a Reply