5

I am new to C. When I practicing C to covert time sting to structure tm back and forth. I noticed some difference. Please advice what I did wrong.

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

/* 
test different format string to strptime
" %A, %b %d, %X %z %Y "
" %A, %b %d, %X %Z %Y "
*/
int main(int argc,char *argv[])
{

   char date[] = "6 Mar 2001 12:33:45";
   char fmt[80];
   struct tm tm;

   if (argc==1) return 0;
   strcpy(fmt,argv[1]);
   memset(&tm, 0, sizeof(struct tm));
   if (strptime(date,"%d %b %Y %H:%M:%S",&tm)==NULL) printf("error\n");
   char buf[128];
   strftime(buf, sizeof(buf), fmt, &tm);
   printf("%s\n", buf);
   printf("%d\n", tm.tm_isdst);
   if (strptime(buf,fmt,&tm)==NULL) printf("error\n");
   else {
   printf("year: %d; month: %d; day: %d;\n",
         tm.tm_year, tm.tm_mon, tm.tm_mday);
   printf("hour: %d; minute: %d; second: %d\n",
         tm.tm_hour, tm.tm_min, tm.tm_sec);
   printf("week day: %d; year day: %d\n", tm.tm_wday, tm.tm_yday);
   }
   return 0;
}

When I use " %A, %b %d, %X %z %Y " as conversion format argument, the code provide some result as follow:

 ~/user$ ./test_time " %A, %b %d, %X %z %Y "
 Tuesday, Mar 06, 12:33:45 +0000 2001 
 0
 year: 101; month: 2; day: 6;
 hour: 12; minute: 33; second: 45
 week day: 2; year day: 64

When I change argument to " %A, %b %d, %X %Z %Y ", the code can not parse the time string which is generated by strftime with exactly the same format.

 ~/user$ ./test_time " %A, %b %d, %X %Z %Y "
  Tuesday, Mar 06, 12:33:45 EET 2001 
 0
 error

Did I miss something to let strptime parse timezone names correctly?

Thanks in advance,

Albert

Albert
  • 53
  • 1
  • 3
  • This looks like C to me. Why do you tag it C++ and especially C++11? – Pascal Cuoq Nov 25 '12 at 22:42
  • @Pascal Cuoq You are right. It is C code. I compiled it with g++. Shouldn't matter, right? – Albert Nov 25 '12 at 22:45
  • As long as you keep the following list of differences to mind, it shouldn't. http://stackoverflow.com/questions/10461331/what-are-the-incompatible-differences-betweeen-c99-and-c11 . And that page does not even seem to list my favorites: in C++, 'c' has type `char` and "c" has type `const char*`. – Pascal Cuoq Nov 25 '12 at 22:47

1 Answers1

10

I'm not sure what you're doing will work. The glibc source code at github has this to say on the matter:

case 'Z':
    /* XXX How to handle this? */
    break

followed by some slightly more "meaty" handling of the lowercase 'z' stuff :-)

So what's most likely happening here is that the string pointer isn't advancing past the EET when the format string is %Z, so that when it tries to process %Y, it complains, rightly so, that EET is not a valid year. This is confirmed by the simple case of "%%" where the code actually does advance the input string pointer rp:

case '%':
    /* Match the `%' character itself.  */
    match_char ('%', *rp++);
    break;

The Linux man page also states on the extensions (of which 'Z' is one):

For reasons of symmetry, glibc tries to support for strptime() the same format characters as for strftime(3). (In most cases the corresponding fields are parsed, but no field in tm is changed.)

In addition the GNU docs state (my italics):

%Z: The timezone name. Note: Currently, this is not fully implemented. The format is recognized, input is consumed but no field in tm is set.

So I actually consider this a bug, albeit one that can be easily fixed with a documentation change to stop pretending it can handle Z-type timezones.

I cannot find any relevant bug in bugzilla so I've raised a bug on glibc there. You can track it here.


Addendum: as per the bug report link in the previous paragraph and the glibc 2.19 release notice, the change I suggested has been made to align the code with the documentation. Hopefully, there's no bugs in it or I'm going to look pretty silly given it's only five lines of code.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Sounds reasonable. According to [man strptime.3](http://www.kernel.org/doc/man-pages/online/pages/man3/strptime.3.html), I was expecting similar implementation as **strftime**. Is it so difficult to specify non-supported descriptors? – Albert Nov 25 '12 at 22:57
  • Your expectation was more than reasonable, I had it myself. As Yoda would say: "Support. Or support not. There is no 'try'." They should either implement this or stop pretending that it exists. When I get to a real PC (this Android tab is a pain to type with), I'll look into filing a bug report. – paxdiablo Nov 25 '12 at 23:05