“mktime” slow? use custom function.

Recently I was working on stream of timestamps in ASCII (C string) format. To do different calculations we mostly need to convert timestamp strings to epoch ticks. Standard C library provides “mktime” function which takes struct tm to be filled and passed as an argument to mktime function. Function works fine if you are not using it very frequently. But if you need to convert millions of conversion at runtime then this function becomes a bottle neck on the performance of your application. I didn’t get any chance to go through the source code/assembly of mktime so I am not sure why this function is so expensive. But I just tried to implement my custom function to do the same conversion what “mktime” does. Results were unbelieveable. I ran one million calls of each function and here are the results:

 mktime: 2950000 microseconds
 time_to_epoch: 60000 microseconds

Here is source code:

time_t time_to_epoch ( const struct tm *ltm, int utcdiff ) {
   const int mon_days [] =
      {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   long tyears, tdays, leaps, utc_hrs;
   int i;

   tyears = ltm->tm_year – 70 ; // tm->tm_year is from 1900.
   leaps = (tyears + 2) / 4; // no of next two lines until year 2100.
   //i = (ltm->tm_year – 100) / 100;
   //leaps -= ( (i/4)*3 + i%4 );
   tdays = 0;
   for (i=0; i < ltm->tm_mon; i++) tdays += mon_days[i];

   tdays += ltm->tm_mday-1; // days of month passed.
   tdays = tdays + (tyears * 365) + leaps;

   utc_hrs = ltm->tm_hour + utcdiff; // for your time zone.
   return (tdays * 86400) + (utc_hrs * 3600) + (ltm->tm_min * 60) + ltm->tm_sec;
}

void str_to_tm ( char *mdate, char *mtime, struct tm* mtm ) {
   char *pstr;
   long year, month, day, hour, min, sec;

   year = strtol( mdate, &pstr, 10 );
   month = strtol( ++pstr, &pstr, 10 );
   day = strtol( ++pstr, &pstr, 10 );

   hour = strtol( mtime, &pstr, 10 ); while( !isdigit(*pstr) ) ++pstr;
   min = strtol( pstr, &pstr, 10 ); while( !isdigit(*pstr) ) ++pstr;
   sec = strtol( pstr, &pstr, 10 );

   mtm->tm_sec = sec;
   mtm->tm_min = min;
   mtm->tm_hour = hour;
   mtm->tm_mday = day;
   mtm->tm_mon = month – 1;
   mtm->tm_year = year – 1900;
}

int main ( int argc, char *argv[] ) {
   char mydate[] = “2010-11-30”;
   char mytime[] = “11:30:45″;

   struct tm mtm;
   time_t ticks, mytcks;

   str_to_tm ( mydate, mytime, &mtm );

   mytcks = time_to_epoch ( &mtm, 5 );

   ticks = mktime ( &mtm );

   printf ( ” std func time : %s”, asctime( localtime( &ticks ) ) );
   printf ( ” our func time : %s”, asctime( localtime( &mytcks ) ) );
   printf ( ” stdlib func ticks : %ld \n”, ticks );
   printf ( ” our func ticks : %ld \n”, mytcks );
}

Output:

std func time : Tue Nov 30 11:30:45 2010
our func time : Tue Nov 30 11:30:45 2010
std func ticks : 1291134645
our func ticks : 1291134645

Advertisements

One Response to ““mktime” slow? use custom function.”

  1. Olaf Dietsche Says:

    Nice post, but two nitpicks:

    – This works with UTC only. If you use DST, you’re off by an hour
    every now and then.

    – If you sum the days in mon_days[], you can save the for() loop,
    e.g.

    mon_days[] = {0, 31, 31 + 28, 31 + 28 + 31, …};
    tdays = mon_days[ltm->tm_mon];

    Regards, Olaf

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


%d bloggers like this: