strptime in c with timezone offsets

VMills picture VMills · Sep 6, 2011 · Viewed 9.2k times · Source

I'm having trouble finding a way to parse the timezone out of strings like the following: "Thu, 1 Sep 2011 09:06:03 -0400 (EDT)"

What I need to do in the larger scheme of my program is take in a char* and convert it to a time_t. The following is a simple test program I wrote to try and figure out if strptime was accounting for timezone at all, and it doesn't appear to be (when this test program executes all the printed numbers are the same when they should differ). Suggestions?

I also tried to use the GNU getdate and getdate_r, because that looks like a better option for possibly flexible formats, but I got a "implicit function declaration" warning from the compiler, implying I wasn't including the correct libraries. Is there something else I should be #include-ing to use getdate ?

#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>

#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
#include <time.h>

int main (int argc, char** argv){

char *timestr1, *timestr2, *timestr3;
struct tm time1, time2, time3;
time_t timestamp1, timestamp2, timestamp3;

timestr1 = "Thu, 1 Sep 2011 09:06:03 -0400 (EDT)"; // -4, and with timezone name
timestr2 = "Thu, 1 Sep 2011 09:06:03 -0000"; // -0

strptime(timestr1, "%a, %d %b %Y %H:%M:%S %Z", &time1); //includes UTC offset
strptime(timestr2, "%a, %d %b %Y %H:%M:%S %Z", &time2); //different UTC offset
strptime(timestr1, "%a, %d %b %Y %H:%M:%S", &time3); //ignores UTC offset

time1.tm_isdst = -1;
timestamp1 = mktime(&time1);
time2.tm_isdst = -1;
timestamp2 = mktime(&time2);
time3.tm_isdst = -1;
timestamp3 = mktime(&time3);

printf("Hello \n");
printf("%d\n%d\n%d\n", timestamp1, timestamp2, timestamp3);
printf("Check the numbers \n");
return 0;
}

Answer

Jonathan Leffler picture Jonathan Leffler · Sep 8, 2011

On MacOS X (10.7.1), one of the 'bugs' listed in the strptime(3) manual page is:

The %Z format specifier only accepts time zone abbreviations of the local time zone, or the value "GMT". This limitation is because of ambiguity due to of the over loading of time zone abbreviations. One such example is EST which is both Eastern Standard Time and Eastern Australia Summer Time.

Some time ago, I wrote a pair of commands - timestamp (May 1989 for revision 1.1) and strptime (July 2007 for revision 1.1). These are relatively thin covers over the strftime() and strptime() functions.

Running them on MacOS X, I get:

$ strptime -T '%Y-%m-%dT%H:%M:%S %Z' 2011-09-08T21:00:00PDT
1315540800 = 2011-09-08T21:00:00PDT
$ timestamp 1315540800
1315540800 = Thu Sep 08 21:00:00 2011
$ timestamp -u 1315540800
1315540800 = Fri Sep 09 04:00:00 2011
$ strptime -T '%Y-%m-%dT%H:%M:%S %Z' 2011-09-08T21:00:00GMT
1315515600 = 2011-09-08T21:00:00GMT
$ timestamp 1315515600
1315515600 = Thu Sep 08 14:00:00 2011
$ timestamp -T '%Y-%m-%dT%H:%M:%S %z' 1315515600
1315515600 = 2011-09-08T14:00:00 -0700
$

I'm in US/Pacific (or America/Los_Angeles, or Pacific Daylight Time; UTC-07:00), so what these commands show is that (as the manual page says), strptime() recognizes PDT and GMT and gives appropriate answers for each. The -u option to timestamp indicates 'print UTC (aka GMT) time' rather than local time. And 9 pm in UTC is indeed 2 pm in PDT.

Contact me if you would like the source - see my profile.