5

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;
}
VMills
  • 183
  • 3
  • 4
  • 12
  • 1
    I'm not sure you should be using the `#endif` directive after defining `__USE_XOPEN`, try putting it after `#include ` –  Sep 06 '11 at 20:15
  • 1
    You should **never** define `__USE_XOPEN`. This is an internal macro of the glibc header implementation, automatically defined based on the presence/value of the `_XOPEN_SOURCE` macro. – R.. GitHub STOP HELPING ICE Sep 06 '11 at 21:01
  • @andrew changing the order of #endif doesn't seem to make a difference either way – VMills Sep 07 '11 at 14:26
  • @R. admittedly in the test program if I take out the _USE_XOPEN it doesn't complain, but for some reason in the context of the actual program I'm working on, without _USE_XOPEN I get the compiler warning of "implicit declaration of function 'strptime'" on a literally identical call to those used in the program above. Why would that be? – VMills Sep 07 '11 at 14:28
  • I am not sure what you are looking for. But you should be aware that the timezone acronym is good for one thing only: Tossing it away. Did you know that there are *several* time zones in the world called "CST", all with different UTC offsets? – DevSolar Sep 07 '11 at 14:37
  • 1
    Make sure you have either not defined any feature-test macros (_*_SOURCE) or that you defined at least `_XOPEN_SOURCE` to a value of at least 600 (preferably 700) **at the top of your source before any `#include` directives**. – R.. GitHub STOP HELPING ICE Sep 07 '11 at 14:39
  • You can probably fix the warning about `getdate()` and `getdate_r()` with `#define _GNU_SOURCE`, parallel to, but different from, `_XOPEN_SOURCE` and `_POSIX_SOURCE` and `_POSIX_C_SOURCE`. The latter two exist; you are better off simply setting `_XOPEN_SOURCE` as already advised (setting `_XOPEN_SOURCE` will effectively set the POSIX source macros correctly). – Jonathan Leffler Sep 07 '11 at 14:59

1 Answers1

4

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278