On macOS Sierra 10.12.2 with GCC 6.3.0, the following code works:
#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef lint
extern const char jlss_id_settz_c[];
const char jlss_id_settz_c[] = "@(#)$Id: settz.c,v 1.2 2017/01/23 07:06:21 jleffler Exp $";
#endif
static void time_convert(time_t t0, char const *tz_value)
{
char old_tz[64] = "-none-";
char *tz = getenv("TZ");
if (tz != 0)
strcpy(old_tz, tz);
setenv("TZ", tz_value, 1);
tzset();
char new_tz[64];
strcpy(new_tz, getenv("TZ"));
char buffer[64];
struct tm *lt = localtime(&t0);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
if (strcmp(old_tz, "-none-") == 0)
unsetenv("TZ");
else
setenv("TZ", old_tz, 1);
tzset();
printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz);
}
int main(void)
{
time_t t0 = time(0);
char *tz = getenv("TZ");
if (tz != 0)
time_convert(t0, tz);
time_convert(t0, "UTC0");
time_convert(t0, "IST-5:30");
time_convert(t0, "EST5");
time_convert(t0, "EST5EDT");
time_convert(t0, "PST8");
time_convert(t0, "PST8PDT");
}
By default, TZ
is not set in the environment — those ungainly tests for getenv("TZ")
returning NULL are necessary to handle that. When run, the output is:
$ ./settz
1485155290 = 2017-01-23 07:08:10 (TZ=UTC0)
1485155290 = 2017-01-23 12:38:10 (TZ=IST-5:30)
1485155290 = 2017-01-23 02:08:10 (TZ=EST5)
1485155290 = 2017-01-23 02:08:10 (TZ=EST5EDT)
1485155290 = 2017-01-22 23:08:10 (TZ=PST8)
1485155290 = 2017-01-22 23:08:10 (TZ=PST8PDT)
$
With the environment set so TZ=US/Alaska
, the output is:
$ TZ=US/Alaska ./settz
1485155395 = 2017-01-22 22:09:55 (TZ=US/Alaska)
1485155395 = 2017-01-23 07:09:55 (TZ=UTC0)
1485155395 = 2017-01-23 12:39:55 (TZ=IST-5:30)
1485155395 = 2017-01-23 02:09:55 (TZ=EST5)
1485155395 = 2017-01-23 02:09:55 (TZ=EST5EDT)
1485155395 = 2017-01-22 23:09:55 (TZ=PST8)
1485155395 = 2017-01-22 23:09:55 (TZ=PST8PDT)
$
This is ugly as a technique; it is also not fast. However, on some platforms, it does in fact work.