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

... to get local time offset ... relative to UTC?

@Serge Ballesta answer is good. So I though I would test it and clean-up a few details. I would have posted as a comment but obviously too big for that. I only exercised it for my timezone, but though others may want to try on their machine and zone.

I made to community wiki as not to garner rep. Imitation is the sincerest form of flattery

This answer is akin to @trenki except that it subtracts nearby struct tm values instead of assuming DST shift is 1 hour and time_t is in seconds.

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

// return difference in **seconds** of the tm_mday, tm_hour, tm_min, tm_sec members.
long tz_offset_second(time_t t) {
  struct tm local = *localtime(&t);
  struct tm utc = *gmtime(&t);
  long diff = ((local.tm_hour - utc.tm_hour) * 60 + (local.tm_min - utc.tm_min))
          * 60L + (local.tm_sec - utc.tm_sec);
  int delta_day = local.tm_mday - utc.tm_mday;
  // If |delta_day| > 1, then end-of-month wrap 
  if ((delta_day == 1) || (delta_day < -1)) {
    diff += 24L * 60 * 60;
  } else if ((delta_day == -1) || (delta_day > 1)) {
    diff -= 24L * 60 * 60;
  }
  return diff;
}

void testtz(void) {
  long off = -1;
  int delta = 600;
  for (time_t t = 0; t < LONG_MAX-delta; t+=delta) {
    long off2 = tz_offset_second(t);

    // Print time whenever offset changes.
    if (off != off2) {
      struct tm utc = *gmtime(&t);
      printf("%10jd %04d-%02d-%02dT%02d:%02d:%02dZ\n", (intmax_t) t,
              utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday,
              utc.tm_hour, utc.tm_min, utc.tm_sec);
      struct tm local = *localtime(&t);
      off = off2;
      printf("%10s %04d-%02d-%02d %02d:%02d:%02d %2d %6ld\n\n", "",
              local.tm_year + 1900, local.tm_mon + 1, local.tm_mday,
              local.tm_hour, local.tm_min, local.tm_sec, local.tm_isdst ,off);
      fflush(stdout);
    }
  }
  puts("Done");
}

Output

                                  v----v  Difference in seconds
         0 1970-01-01T00:00:00Z
           1969-12-31 18:00:00  0 -21600

   5731200 1970-03-08T08:00:00Z
           1970-03-08 03:00:00  1 -18000

  26290800 1970-11-01T07:00:00Z
           1970-11-01 01:00:00  0 -21600

...

2109222000 2036-11-02T07:00:00Z
           2036-11-02 01:00:00  0 -21600

2120112000 2037-03-08T08:00:00Z
           2037-03-08 03:00:00  1 -18000

2140671600 2037-11-01T07:00:00Z
           2037-11-01 01:00:00  0 -21600

Done

Does your system's strftime() function support the %z and %Z specifiers? On FreeBSD,

 %Z    is replaced by the time zone name.

 %z    is replaced by the time zone offset from UTC; a leading plus sign
       stands for east of UTC, a minus sign for west of UTC, hours and
       minutes follow with two digits each and no delimiter between them
       (common form for RFC 822 date headers).

and I can use this to print this:

$ date +"%Z: %z"
CEST: +0200

ISO C99 has this in 7.23.3.5 The strftime function:

%z     is replaced by the offset from UTC in the ISO 8601 format
       ‘‘−0430’’ (meaning 4 hours 30 minutes behind UTC, west of Greenwich),
       or by no characters if no time zone is determinable. [tm_isdst]
%Z     is replaced by the locale’s time zone name or abbreviation, or by no
       characters if no time zone is determinable. [tm_isdst]

This C code computes the local time offset in minutes relative to UTC. It assumes that DST is always one hour offset.

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

int main()
{
    time_t rawtime = time(NULL);
    struct tm *ptm = gmtime(&rawtime);
    time_t gmt = mktime(ptm);
    ptm = localtime(&rawtime);
    time_t offset = rawtime - gmt + (ptm->tm_isdst ? 3600 : 0);

    printf("%i\n", (int)offset);
}

It uses gmtime and localtime though. Why don't you want to use those functions?

Tags:

Time

C

Utc

Offset