This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Need hints on parsing time strings


Hi,

I'm trying to parse date/time strings which look like:

    2009-04-14T13:00:00 CEST
    2009-04-14T13:00:00+0
    2009-04-14T13:00:00+Z
    2009-04-14T13:00:00CEST
    2009-04-14T13:00:00 CET

You get the idea. My questions:

 (Q1) Is strptime the right approach?
 (Q2) Does strptime help me with the timezone thing?

My approach at the moment is (yes, it is awkward, so I guess I'm doing
someething wrong):

  (1) parse the string first with "%FT%T%z" to see whether it "makes
      sense"

        strftime(datetime, "%FT%T%z", &tm);

  (2) re-parse it with ""%FT%T" to get hold of the time zone part

        char *tz = strftime(datetime, "%FT%T%z", &tm);

      (the return value of strftime should now point at (the beginning
      of) the assumed time zone part, right?)

  (3) Convert the whole struct tm to a time_t, whithin the time zone
      gathered in (2); that's achieved by temporarily setting the TZ
      environment variable to whatever timezone we have:

        char *oldtz = getenv("TZ");
        if(tz && *tz) setenv("TZ", tz, 1); else setenv("TZ, "", 1); /* want UTC as default */
        time_t tim = mktime(&tm);
	if(oldtz) setenv("TZ", oldtz, 1); else unsetenv("TZ");

        (This raises te next question:

  (Q3) How does that work in multithreaded environments?)

Needless to say, this doesn't always work: the timezone database has
entries for CET (for example), but not for CEST (I'm on some vanilla
GNU/Linux, more or less current Debian).

Attached is a little test program which does roughly what I outlined
above.

Am I missing something? Am I better off cooking up something by myself?

Thanks a million for any hints

Regards
-- tomás
/* tform.c
   test bench for iso8601 transform
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

static char*
localizetime(char *datetime, char *format);

int main(int argc, char *argv[]) {
  switch(argc) {
    case 3:
      printf("%s\n", localizetime(argv[1], argv[2]));
      break;
    case 2:
      printf("%s\n", localizetime(argv[1], NULL));
      break;
    default:
      printf("Usage: %s <datetime> [<output format>]\n", argv[0]);
      break;
  }
}

static char*
localizetime(char *datetime, char *format){
  struct tm  tm_in;
  struct tm  tm_out;
  time_t tim;
  static char timbuf[255]; /* CAREFUL */

  memset(&tm_in, 0, sizeof(struct tm)); 
  memset(&tm_out, 0, sizeof(struct tm)); 
  /* if(!format) format = "%c"; */
  format = "%F %T";

  if(datetime) { /* parse */
    char *rest = NULL; /* unparsed debris from strptime or target timezone */
    char *oldtz = NULL; /* old timezone, for restore */
    /* parse the given timestamp into a tm struct.
       Parse twice. Once with timezone, to check validity (debris must be empty)... */
    rest = strptime(datetime, "%FT%T%z", &tm_in);
    if (rest && *rest) { /* some debris */
      printf("zeit:format-iso-8601: Could not successfully parse ISO-8601 date '%s' -- unparsed '%s'\n", datetime, rest);
      goto FAIL;
    }
    /* ...and a second time without timezone (debris is now timezone) */
    rest = strptime(datetime, "%FT%T", &tm_in);
    /* switch to this timezone: FIXME this is not thread safe!
       Cf. Linux manpage for timegm(3) for this shenanigan */
    while(isspace(*rest)) rest++;
    printf("  timezone='%s'\n", rest);
    oldtz = getenv("TZ");
    if(rest && *rest) setenv("TZ", rest, 1);
    else unsetenv("TZ");
    tzset();
    tim = mktime(&tm_in);
    if(oldtz) setenv("TZ", oldtz, 1);
    else unsetenv("TZ");
    tzset();
  } else { /* no date time: now */
    tim = time(NULL);
  }

  /* to local time */
  localtime_r(&tim, &tm_out);
  /* format tm struct according to format string passed in */
  strftime(timbuf, sizeof(timbuf), format, &tm_out);
  return timbuf;
 FAIL: 
  return "--";
}

Attachment: sample
Description: Text document

Attachment: signature.asc
Description: Digital signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]