oz123
oz123

Reputation: 28868

strftime force output in same local timezone

My current computer gives the time with CET:

$ date
Mon Dec  1 21:31:41 CET 2014

However my locale is en_US:

$ locale | grep -i time
LC_TIME="en_US.UTF-8"

I would like to format an epoch string with C to my current local time zone, but I don't know how to tell strptime to change the default local:

#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int
main(void)
{
   struct tm tm;
   char buf[255];

   memset(&tm, 0, sizeof(struct tm));
   strptime("1412200800", "%s", &tm);
   strftime(buf, sizeof(buf), "%c %Z", &tm);
   puts(buf);
   exit(EXIT_SUCCESS);
}

The man page states that it formats the time according to the locale, but it seems to ignore my setting:

 $ export LC_TIME=de_DE.UTF-8
 $ locale | grep -i time
LC_TIME=de_DE.UTF-8
 $ ./a.out 
Thu Oct  2 00:00:00 2014 CEST

What I expect is:

Wed Thu Oct  1 22:00:00 2014 CET

update

OK, so I completely removed %s and tried the following approach, but still no success:

#define _XOPEN_SOURCE
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

int
main(void)
{
   struct tm *tim;
   setlocale(LC_ALL, "");
   char buf[255];
   time_t c;

   c = strtoul("1412200800", NULL, 0);
   tim = localtime(&c);
   strftime(buf, sizeof(buf), "%c" , tim);
   puts(buf);
   printf("%s %s\n", tzname[0], tzname[1]);
   exit(EXIT_SUCCESS);
}

The output is still now what I'd expect:

gcc strptime_test.c && ./a.out 
Thu 02 Oct 2014 12:00:00 AM CEST
CET CEST

update 2, the solution:

Instead of using localtime(&c); I now use:

tim = gmtime(&c);
strftime(buf, sizeof(buf), "%c" , tim);

Which give the desired behaviour:

Wed 01 Oct 2014 10:00:00 PM GMT

Upvotes: 1

Views: 1773

Answers (1)

M.M
M.M

Reputation: 141628

Your code is using a non-standard glibc extension to strptime; %s is the number of seconds since epoch.

According to Epoch Converter, 1412200800 is Wed, 01 Oct 2014 22:00:00 GMT so your program is behaving correctly. However, it's unclear whether epoch seconds are to be taken in UTC, or in your local timezone, so as loreb notes in comments you may also need to call a time-zone conversion function.

You will have to make a decision as to whether times (i.e. contents of time_t and struct tm objects) in your program are times in UTC, or local times.

I would suggest the following fix: replace strptime with

time_t c = 1412200800;
tm = *gmtime(&c);     

The other function that might be used here instead of gmtime is localtime.


BTW I think you are mixing up locales and timezones: "locale" means the way that the time is formatted; for example the default might be:

Sun Oct  1 00:00:00 2014

but the locale-formatted version would be:

Sun, Oct 01, 2014 12:00:00 AM

Time-zones and locales are different things. (One locale may span multiple timezones, and one timezone may contain multiple locales).

NB. in C, the default locale is the C locale, not the system one. To read locale from environment variables, do:

#include <locale.h>

// in main()
setlocale(LC_ALL, "");

Upvotes: 1

Related Questions