C: How to print a specific time value in a specific time zone (by offset)?

I am writing a C application that analyzes data files written by an external program (which I do not control). It stores binary data, one field of which is time in the standard UNIX "era" format (seconds since January 1, 1970, UTC).

Another field is the time zone saved as the offset in seconds from UTC.

Cool, I have everything I need for the date / time string to represent this information in the time zone in which it was written, right? Well ... that doesn't seem to be, and / or I'm not sure how to do it.

I threw things back to a fairly simple test:

#include <stdio.h> #include <time.h> int main(void) { time_t t; struct tm *tm; char buf[BUFSIZ]; int offset = 4980; /* slightly bizarre, just to test this - an hour * and 23 minutes ahead of UTC */ t = time(NULL); tm = localtime(&t); strftime(buf, BUFSIZ, "%FT%T%z", tm); printf("before: %s\n", buf); /* since we're not telling localtime anything different, * compensate here (by subtracting applied offset, and adding * desired one): */ t += offset - tm->tm_gmtoff; tm = localtime(&t); tm->tm_zone = "XYZ"; // not used -- but it was in an earlier version tm->tm_gmtoff = offset; // on macos, I used to also have %+, which referenced tm_zone strftime(buf, BUFSIZ, "%FT%T%z", tm); printf("after: %s\n", buf); return 0; } 

When I run this on MacOS X 10.6, I get:

 before: 2011-02-23T00:53:04-0800 after: 2011-02-23T10:16:04-0800 

What would I expect (and actually get in a Linux box):

 before: 2011-02-23T00:53:04-0800 after: 2011-02-23T10:16:04+0123 

Do I need to change the TZ environment variable (and maybe call tzset )? There seems to be a way to manipulate data structures and get the right things, but of course this does not work (on MacOS X 10.6, anyway, works fine on Linux).

As a workaround, I suppose I can remove% z from my format string and create this part myself.

Ideally, however, I would like to have either a modification of my struct tm , or some other function call that I can use (e.g. strftime, but with an extra parameter or something else, or maybe an alternative form of localtime, instead ), which would make things different.

Since Linux seems to behave (although even there, the above solution is not entirely ideal, because I'm fudging my time_t value, I'd rather have a parameter that changes how struct tm calculated), this is something that I should to report as an error against macOS?

Alternatively, is there any other set of library procedures that I could name, even if it ultimately requires a third-party (something from the GNU library, I present)? I would rather keep C, although I would consider ObjC or C ++ options.

+4
source share
3 answers

I prefer to use mktime() instead of changing the value of time_t . However, this applies to the TZ offset (as well as the localtime() solution), so the implementation of mkgmtime() is required.

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> static void set_timezone(char *tz) { static char var[1024]; snprintf(var, sizeof(var), "TZ=%s", tz); putenv(var); tzset(); } static time_t mkgmtime(struct tm *tm) { char var[1024]; time_t t; snprintf(var, sizeof(var), "%s", getenv("TZ") ? getenv("TZ") : ""); set_timezone("GMT0"); t = mktime(tm); set_timezone(var); return t; } int main(void) { time_t t; struct tm tm; char buf[BUFSIZ]; int offset = 4980; /* slightly bizarre, just to test this - an hour * and 23 minutes ahead of UTC */ t = time(NULL); tm = *localtime(&t); strftime(buf, BUFSIZ, "%FT%T%z", &tm); printf("before: %s\n", buf); tm = *gmtime(&t); tm.tm_sec += offset; mkgmtime(&tm); strftime(buf, BUFSIZ, "%FT%T%z", &tm); printf("after: %s\n", buf); return 0; } 
+2
source

I think a better approach would be

  • read your value in time_t variable;

  • set the TZ environment variable by following these guidelines. See Also this page for information on how you should specify TZ;

  • invoke localtime() .

This should be guaranteed to work, although I cannot test it on a MacOS platform.

0
source

I personally like to embed small python scripts in my bash code. Python has many powerful ready-made libraries for features like you.

You can insert python code in a bash script like this (suppose python is installed)

 python << END from pytz import timezone south_africa = timezone('Africa/Johannesburg') sa_time = datetime.now(south_africa) print sa_time.strftime('%Y-%m-%d_%H-%M-%S') END 

You can change the time zone setting as you want to display in different time zones. See http://pytz.sourceforge.net/ for more details.

-1
source

Source: https://habr.com/ru/post/1340930/


All Articles