Unix C++: get time at a different zone Unix C++: get time at a different zone unix unix

Unix C++: get time at a different zone


Since you said "UNIX", this uses TZ, but, TZ=[what goes here] You need to find out [what goes here] on your system. It might be "America/LosAngeles" or one of several other strings for PST.If your system is POSIX: TZ=PST8PST is guaranteed to work. But it may not be optimal.

Primitive non-production code assumes TZ is not currently in use. This is in C, not C++ since your tag was C:

setenv("TZ", "PST8PST", 1);   // set TZtzset();                // recognize TZtime_t lt=time(NULL);   //epoch secondsstruct tm *p=localtime(&lt); // get local time struct tmchar tmp[80]={0x0};strftime(tmp, 80, "%c", p);  // format time use format string, %c printf("time and date PST: %s\n", tmp); // display time and date// you may or may not want to remove the TZ variable at this point.


I have the following C code stashed away to deal with the problem. Efficiency isn't the first word that springs to mind (two calls to setenv(), two calls to tzset()), but the standard C library doesn't make it easy to do better:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>static void time_convert(time_t t0, char const *tz_value){    char old_tz[64];    strcpy(old_tz, getenv("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);    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");    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");}

In your original code, you have to worry about normalizing the time structure after changing the hour offset. You can do that with the mktime() function. Here's a program based on the function in the question, which is pure C and avoids the problems of returning a pointer to a local variable (and the #define ending with a semi-colon):

#include <assert.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <time.h>#define PST (-8)extern int getSecondSystemTime(char *buffer, size_t buflen);int getSecondSystemTime(char *buffer, size_t buflen){    time_t rawtime = time(0);;    struct tm *timeinfo;    char t_buff[32];    timeinfo = gmtime(&rawtime);    timeinfo->tm_hour = timeinfo->tm_hour + PST;    time_t pst_time = mktime(timeinfo);    assert(pst_time != (time_t)-1);    int len = strftime(t_buff, sizeof(t_buff), "%Y-%m-%d %H:%M:%S", timeinfo);    assert(len != 0);    int rv = snprintf(buffer, buflen, "%ld = %s (%s)", (long)rawtime, t_buff,                       "Pacific Time (US & Canada)");    assert(rv > 0);    return rv;}int main(void){    char buffer[128];    getSecondSystemTime(buffer, sizeof(buffer));    printf("%s\n", buffer);    return(0);}

Clearly, a better interface would pass the UTC time value and the time zone offset (in hours and minutes) as arguments. Despite the fact that my computer runs in US/Pacific (or America/Los_Angeles) time zone by default, I tested with TZ set to various values (including US/Eastern, IST-05:30) and got the correct values out; I'm reasonably convinced based on past experience that the calculation is correct.

I have another program that attempts to dissect whether the -1 returned from mktime() is because of an error or because the converted time corresponds to (time_t)-1:

/* Attempt to determine whether time is really 1969-12-31 23:59:59 +00:00 */static int unix_epoch_minus_one(const struct tm *lt){    printf("tm_sec = %d\n", lt->tm_sec);    if (lt->tm_sec != 59)        return(0);    printf("tm_min = %d\n", lt->tm_min);    /* Accounts for time zones such as Newfoundland (-04:30), India (+05:30) and Nepal (+05:45) */    if (lt->tm_min % 15 != 14)        return(0);    /* Years minus 1900 */    printf("tm_year = %d\n", lt->tm_year);    if (lt->tm_year != 69 && lt->tm_year != 70)        return(0);    printf("tm_mday = %d\n", lt->tm_mday);    if (lt->tm_mday != 31 && lt->tm_mday != 1)        return(0);    /* Months 0..11 */    printf("tm_mon = %d\n", lt->tm_mon);    if (lt->tm_mon != 11 && lt->tm_mon != 0)        return(0);    /* Pretend it is valid after all - though there is a small chance we are incorrect */    return 1;}


Here is a cleaner way of doing this (this example gets GMT time including DST bias):

struct STimeZoneFromRegistry{   long  Bias;   long  StandardBias;   long  DaylightBias;   SYSTEMTIME StandardDate;   SYSTEMTIME DaylightDate;};static SYSTEMTIME GmtNow(){   FILETIME UTC;   GetSystemTimeAsFileTime(&UTC);    SYSTEMTIME GMT;   TIME_ZONE_INFORMATION tz = {0};   STimeZoneFromRegistry binary_data;   DWORD size = sizeof(binary_data);   HKEY hk = NULL;   TCHAR zone_key[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT Standard Time");   if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, zone_key, 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS) &&      (RegQueryValueEx(hk, "TZI", NULL, NULL, (BYTE *) &binary_data, &size) == ERROR_SUCCESS))   {      tz.Bias = binary_data.Bias;      tz.DaylightBias = binary_data.DaylightBias;      tz.DaylightDate = binary_data.DaylightDate;      tz.StandardBias = binary_data.StandardBias;      tz.StandardDate = binary_data.StandardDate;   }   SystemTimeToTzSpecificLocalTime(&tz, &UTC, &GMT);   return GMT; }