Home > Net >  I need to get time in California, but I am from Novosibirsk
I need to get time in California, but I am from Novosibirsk

Time:09-12

I have this code that gives me local time.

#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

extern char *tzname[];

main(){
    time_t now;
    struct tm *sp;

    (void) time( &now );

     printf("%s", ctime( &now ) );

     sp = localtime(&now);
     printf("%d/%d/d %d:d %s\n",
         sp->tm_mon   1, sp->tm_mday,
         sp->tm_year, sp->tm_hour,
         sp->tm_min, tzname[sp->tm_isdst]);
     exit(0);
}

What is the best way to get time in California using C language (or another time zone)?

CodePudding user response:

This program uses putenv() to set the time zone environment variable, tzset() to alert the C runtime that the time zone might have changed, and then uses localtime() and strftime() to analyze the time.


#include <stdio.h>
#include <time.h>
#include <unistd.h>     /* putenv() */
#include <stdlib.h>

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

static char *arg0;

static char tznames[][32] =
{
    "TZ=US/Pacific",
    "TZ=US/Mountain",
    "TZ=US/Central",
    "TZ=US/Eastern",
    "TZ=UK",
    "TZ=UTC",
    "TZ=UTC0",
    "TZ=Australia/NSW",
    "TZ=Australia/North",
    "TZ=Australia/Queensland",
    "TZ=Australia/South",
    "TZ=Australia/Tasmania",
    "TZ=Australia/Victoria",
    "TZ=Australia/West",
    "TZ=GMT",
    "TZ=GMT-1",
    "TZ=GMT 1",
    "TZ=PST8PDT",
    "TZ=CST6CDT",
    "TZ=GMT0BST",
};

static void tz_time(char *tz, time_t t0)
{
    if (putenv(tz) != 0)
    {
        fprintf(stderr, "%s: putenv(%s) failed\n", arg0, tz);
        exit(EXIT_FAILURE);
    }
    tzset();
    struct tm *lt = localtime(&t0);
    char buffer[64];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %z", lt);
    printf("%-24s: %lu = %s\n", tz, (unsigned long)t0, buffer);
}

int main(int argc, char **argv)
{
    if (argc > 0)
        arg0 = argv[0];

    time_t t0 = time(0);

    for (size_t i = 0; i < DIM(tznames); i  )
        tz_time(tznames[i], t0);

    return(0);
}

I'm not convinced that UK really works — it probably ends up as UTC because it isn't recognized. However, sample output is:

TZ=US/Pacific           : 1662917121 = 2022-09-11 10:25:21 -0700
TZ=US/Central           : 1662917121 = 2022-09-11 12:25:21 -0500
TZ=US/Eastern           : 1662917121 = 2022-09-11 13:25:21 -0400
TZ=US/Mountain          : 1662917121 = 2022-09-11 11:25:21 -0600
TZ=UK                   : 1662917121 = 2022-09-11 17:25:21  0000
TZ=UTC                  : 1662917121 = 2022-09-11 17:25:21  0000
TZ=UTC0                 : 1662917121 = 2022-09-11 17:25:21  0000
TZ=Australia/NSW        : 1662917121 = 2022-09-12 03:25:21  1000
TZ=Australia/North      : 1662917121 = 2022-09-12 02:55:21  0930
TZ=Australia/Queensland : 1662917121 = 2022-09-12 03:25:21  1000
TZ=Australia/South      : 1662917121 = 2022-09-12 02:55:21  0930
TZ=Australia/Tasmania   : 1662917121 = 2022-09-12 03:25:21  1000
TZ=Australia/Victoria   : 1662917121 = 2022-09-12 03:25:21  1000
TZ=Australia/West       : 1662917121 = 2022-09-12 01:25:21  0800
TZ=GMT                  : 1662917121 = 2022-09-11 17:25:21  0000
TZ=GMT-1                : 1662917121 = 2022-09-11 18:25:21  0100
TZ=GMT 1                : 1662917121 = 2022-09-11 16:25:21 -0100
TZ=PST8PDT              : 1662917121 = 2022-09-11 10:25:21 -0700
TZ=CST6CDT              : 1662917121 = 2022-09-11 12:25:21 -0500
TZ=GMT0BST              : 1662917121 = 2022-09-11 18:25:21  0100

(This was run on an antique MacBook Pro running macOS Monterey 12.5.1. Said machine will not be allowed to update to macOS Ventura; it is too old in the eyes of Apple and no longer supported.)

Because it uses putenv(), it is not pure standard C (the <unistd.h> header is not part of standard C). It is also not thread-safe because it is messing with the environment. Valid time zone names are not specified by C — notations such as TZ=GMT0BST are specified by POSIX.

There are few people who would argue that the timezone handling in standard C (or even POSIX) are anywhere close to optimal. Frankly, they're appalling.

CodePudding user response:

I would suggest you get the UTC time using gmtime() and then computing the offset for the desired timezone. See the accepted answer in How to convert from UTC to local time in C? for a good tutorial on how to apply these offsets.

CodePudding user response:

There are several ways to do this.

(1) You can set the environment variable TZ before running your program, as suggested by @Useless in a comment.

(2) You can set the environment variable TZ from within your program, using the setenv call. After doing that, you must call tzset() to tell the timezone machinery in the C library to reexamine the environment variable. Here's your program, fleshed out with the necessary calls to setenv and tzset for comparison:

sp = localtime(&now);
printf("%d/%d/d %d:d %s\n",
    sp->tm_mon   1, sp->tm_mday,
    1900   sp->tm_year, sp->tm_hour,
    sp->tm_min, tzname[sp->tm_isdst]);

setenv("TZ", "America/Los_Angeles", 1);
tzset();

sp = localtime(&now);
printf("%d/%d/d %d:d %s\n",
    sp->tm_mon   1, sp->tm_mday,
    1900   sp->tm_year, sp->tm_hour,
    sp->tm_min, tzname[sp->tm_isdst]);

(3) You might be able to use the BSD tzalloc and localtime_rz functions to directly convert to a specified local time zone:

timezone_t tzp = tzalloc("America/Los_Angeles");
if(tzp == NULL) { fprintf(stderr, "no such zone\n"); exit(1); }
struct tm tmbuf;

sp = localtime_rz(tzp, &now, &tmbuf);
printf("%d/%d/d %d:d %s\n",
    sp->tm_mon   1, sp->tm_mday,
    1900   sp->tm_year, sp->tm_hour,
    sp->tm_min, sp->tm_zone);

(In this last example, I have quietly used a completely different method of printing the time zone name.)

Everything else being equal, I would say that #3 is vastly preferable, since passing an explicit argument to a function — in this case, passing tzp to localtime_rz() — is vastly preferable to manipulating a global variable. Unfortunately, however, the tzalloc and localtime_rz functions are not standard, and they're actually rather rare these days, so I won't be at all surprised if they're not available to you. See also this answer.

CodePudding user response:

Just checked. Novosibirsk, with no DST shifting, is (currently) 14hrs ahead of CA (that is currently on DST).

Just take your time ('HH'), add 24, subtract 14 and work it out modulo 24.

Your 22:xx => (22 24 - 14) % 24 => 08:xx

This is valid until CA change their clocks at the end of their (summer-ish) DST phase, reverting to "standard time". During 'winter', use 13 instead of 14.

Any "code" solution worth its salt will also have to account for whether-or-not DST is applicable and the date of change is arbitrary in many jurisdictions.

  • Related