Using strptime to parse ISO 8601 formated timestamps

A lot of dates that come back from XML based web services are in the ISO 8601 form. I found out recently that it isn't straight forward to parse such a date using C functions and have the time come out in the correct timezone. It isn't rocket science but it is a lot more convoluted than higher level languages like Java.

First of lets see an example of the ISO 8601 format:

2006-02-03T16:45:09.000Z

That breaks down into:

<date>T<time><timezone>

Where a timezone of Z is equal to UTC. I was only interested in parsing timestamps in UTC so the following only applies to that timezone.

If you want to know any more about the format check out this page.

The strptime function is a flexible way to turn a string into a struct tm given a specified format. It is like a sscanf for dates. For more information on it check here. I'm not exactly sure of the portability of this function but it seems to be fairly old now so it is probably reasonably portable.

The format used to parse the a ISO 8601 timestamp is: %FT%T%z

That will give you the date in struct tm form. If you were to print the contents of this you would get the timestamp in UTC. For my application I needed to convert it into the local timezone for the machine it was running on. To do that I used the tzset function to populate the timezone. I then use the mktime function to turn the struct tm into a time_t (just a long that represents the number of seconds since the epoch). Now I use the timezone value to remove the correct number of seconds from the time_t to get my local time. Then to wrap it all back up I use the localtime_r function to put it back into struct tm form.

Here is an example:

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

void convert_iso8601(const char *time_string, int ts_len, struct tm *tm_data)
{
  tzset();

  char temp[64];
  memset(temp, 0, sizeof(temp));
  strncpy(temp, time_string, ts_len);

  struct tm ctime;
  memset(&amp;ctime, 0, sizeof(struct tm));
  strptime(temp, "%FT%T%z", &amp;ctime);

  long ts = mktime(&amp;ctime) - timezone;
  localtime_r(&amp;ts, tm_data);
}

int main()
{
  char date[] = "2006-03-28T16:49:29.000Z";
  struct tm tm;
  memset(&amp;tm, 0, sizeof(struct tm));
  convert_iso8601(date, sizeof(date), &amp;tm);

  char buf[128];
  strftime(buf, sizeof(buf), "Date: %a, %d %b %Y %H:%M:%S %Z", &amp;tm);
  printf("%sn", buf);
}

This example compiles with: cc -o timetest timetest.c

Although I haven't tested the code with other timezone encoded ISO 8601 timestamps it seems reasonable that if you have one in that type of format that you could add an extra step and convert it to UTC then into your local timezone without much hassle.

2 thoughts on “Using strptime to parse ISO 8601 formated timestamps

Leave a Reply

Your email address will not be published. Required fields are marked *