Why does glibc “timezone” global not agree with sy

2020-07-10 08:13发布

问题:

I'm experiencing a bizarre issue where my system clock knows that it's daylight savings time, but glibc seems not to. This is an up-to-date Ubuntu installation, and I have checked /etc/localtime and it has the correct changeover time for last week's switch to DST.

The current correct timezone for me is Pacific Daylight Time (UTC-7). When I ask my system what time zone I'm in, it tells me correctly:

$ date +%z
-0700

But when I run the following program:

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

int main() {
  tzset();
  printf("%lu\n", timezone);
  return 0;
}

The output is, incorrectly:

28800

Which corresponds to UTC-8, or Pacific Standard Time. (And no, TZ is not set in my environment)

I thought glibc and the date program would get their time zone information from the same source, but apparently either they don't or I'm misunderstanding how the glibc timezone global works.

The basic questions are then:

  1. Why are these two outputs different
  2. How can I reliably detect the system UTC offset from a C program?

回答1:

I don't think "timezone" changes with daylight time. Try the "daylight" variable. On my system:

      The external variable timezone contains the difference, in seconds,
      between UTC and local standard time (for example, in the U.S. Eastern
      time zone (EST), timezone is 5*60*60).  The external variable daylight
      is non-zero only if a summer time zone adjustment is specified in the
      TZ environment variable.


回答2:

Look at tm.tm_isdst field after doing this:

  time_t current_time;
  struct tm tm;

  current_time = time(NULL);
  localtime_r(&current_time, &tm);

According to the localtime_r(3) manpage, this does actually indicate whether DST is in effect at the time specified. I think you then need to assume that DST adds one hour to the timezone(3) variable you're already using, or do the diff trick against GMT.

Works for me in Australian AEST, hope it works for you.



回答3:

You can use tm_gmtoff mem ber of struct tm which is same as ::timezone but it considers DST and the sign is reversed.

http://www.gnu.org/s/libc/manual/html_node/Time-Zone-Functions.html#Time-Zone-Functions



回答4:

Here is my code for this using tm_gmtoff if linux is defined, and using timezone.tz_minuteswest from gettimofday otherwise (here 'ltm' is the output of localtime):

{
    int tz_offset;

#if defined(__linux__)
    tz_offset= ltm.tm_gmtoff;
#else
    tz_offset= -tz.tz_minuteswest*60 + ltm.tm_isdst*3600;
#endif

     printf ("LT = UTC +d sec\n", tz_offset);
}


标签: c timezone glibc