Search code examples
ctimeoffsetutc

C code to get local time offset in minutes relative to UTC?


I didn't find a trivial way to get the time offset in minutes between the local time and the UTC time.

At first I intended to use tzset() but it doesn't provide the daylight saving time. According to the man page, it is simply an integer different of zero if day light saving is in effect. While it is usually an hour, it may be half an hour in some country.

I would prefer avoiding to compute the time difference between current UTC returned by gmtime() and localtime().

A more general solution would give me this information for a specified location and a positive time_t value, or at least locally.

Edit 1: the use case is to get the right local time offset for https://github.com/chmike/timez. BTW, If you thought libc functions to manipulate time were Ok, read this https://rachelbythebay.com/w/2013/03/17/time/.

Edit 2: the best and simplest solution I have so far to compute the time offset to UTC in minutes is

// Bogus: assumes DST is always one hour
tzset();
int offset = (int)(-timezone / 60 + (daylight ? 60 : 0));

The problem is to determine the real day light saving time.

Edit 3: Inspired by the answer of @trenki, I came up with the following solution. This is a hack in that it tricks mktime() to consider the output of gmtime() as the localtime. The result is inaccurate when the DST change is in the time span between UTC time and localtime.

#include <stdio.h>
#include <time.h>

int main()
{
    time_t rawtime = time(NULL);
    struct tm *ptm = gmtime(&rawtime);
    // Request that mktime() looksup dst in timezone database
    ptm->tm_isdst = -1;                
    time_t gmt = mktime(ptm);
    double offset = difftime(rawtime, gmt) / 60;
    printf("%f\n", offset);
    return 0;
}

Solution

  • I would like to submit yet another answer to this question, one that AFAICS also deals with the IDL.

    This solution depends on timegm and mktime. On Windows timegm is available as _mkgmtime from the CRT, in other words define a conditional macro.

    #if _WIN32
    #    define timegm _mkgmtime
    #endif
    
    int local_utc_offset_minutes ( ) {
        time_t t  = time ( NULL );
        struct tm * locg = localtime ( &t );
        struct tm locl;
        memcpy ( &locl, locg, sizeof ( struct tm ) );
        return (int)( timegm ( locg ) - mktime ( &locl ) ) / 60;
    }