Andrew G
Andrew G

Reputation: 71

tzset and daylight global variable interpretation in time.h

In the time.h header for the daylight global variable it says: "This variable has a nonzero value if Daylight Saving Time rules apply. A nonzero value does not necessarily mean that Daylight Saving Time is now in effect; it means only that Daylight Saving Time is sometimes in effect."

Now I've noticed that in both Solaris 11.2 and Linux the "daylight" variable is being set to 1, even though my time-zone does not use daylight savings at all (Australia/Brisbane).

Sample code confirms this, if I run tzset and output the global variables we get: daylight = 1 tz[0] = [AEST] tz[1] = [AEDT] timezone = [-36000]

But by my understanding, daylight should be set to 0 since my zone does not have daylight savings at any time during the year.

I also noticed that the struct tm when set to current time returns a tm_isdst = 0, which is correct.

So why is the daylight variable set to 1? Shouldn't it be set to 0? Or am I misinterpreting this?

Code is:

#include <stdio.h>
#include <time.h>
void main()
{
  time_t t;
  struct tm     *tms = { 0 };
  tzset();
  time(&t);
  tms = localtime(&t);
  printf("date and time : %s",ctime(&t));
  printf("daylight = %d tz[0] = [%s] tz[1] = [%s] timezone = [%ld]\n", daylight, tzname[0], tzname[1], timezone);
  printf("tm_isdst = %d\n",tms->tm_isdst);
}

Output is:

date and time : Mon Nov 30 16:41:01 2015
daylight = 1 tz[0] = [AEST] tz[1] = [AEDT] timezone = [-36000]
tm_isdst = 0

Upvotes: 6

Views: 7861

Answers (3)

Lawrence K
Lawrence K

Reputation: 1

It's easier if you consider what tzset() does - it installs a timezone definition. That is it interprets the contents of the TZ environment variable, loads a zoneinfo file or similar. One thing tzset() doesn't do is provide information based on any specific time, it doesn't for example look at the system clock or make assumptions about what the current year is. There are standard functions like gmtime(), localtime(), mktime() that deal with specific dates and times. tzset() just sets up the general framework for those functions to work and provides some vary basic information about the overall timezone definition in extern variables. tzset() doesn't tell you if there is daylight saving time now, because it doesn't know or care what "now" is. It can tell you if the overall timezone definition contains any information about daylight saving time, e.g. whether tz[1] is defined.

It seems that some of the documentation is outdated too, as it fails to specify clearly how tzset() presents more modern/complex timezone definitions in its extern variables, but understanding what tzset() does it is mostly clear what to expect from it.

The problem with "daylight" and "timezone" and some documentation is that they were created very early on when timezone definitions were nothing more than a TZ string, which has syntax that can specify names and time offsets and things like "DST starts 1st Sunday March, ends 3rd Sunday October". It contained no historical information, if the rules for a timezone changed then you just changed your TZ variable to implement the new rules. We now have things like the zoneinfo database with historical information, unfortunately the definition of tzset() hasn't keep up with this. It's fine internally: localtime() etc. will do the right thing when tzset() loads a complex timezone, but the simple extern variables can't always give an accurate summary. "daylight" isn't too bad: because tzset() doesn't consider any particular date/time, it is reasonable for it to set "daylight" if there is any daylight saving time defined anywhere in the timezone data, again essentially if tz[1] is defined. In principle pretty much anything in a timezone could change over the years including the timezone names, and the base timezone offset. This rarely happens but some real timezones have an unusual history, not least around the International Date Line.

Upvotes: 0

chux
chux

Reputation: 154156

About the C Standard tm_isdst member.

The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and negative if the information is not available. C11dr §7.27.1 4

This slightly differs from *nix specification about the *nix global variable daylight.
daylight is not part of standard C.


gnu.org reports

Variable: int daylight
This variable has a nonzero value if Daylight Saving Time rules apply. A nonzero value does not necessarily mean that Daylight Saving Time is now in effect; it means only that Daylight Saving Time is sometimes in effect.


The tm_isdst refers to the struct tm timestamp. It only means DST is in effect for that time-stamp.

daylight != 0 implies DST is used sometimes in the timezone's timestamps.

As Australia/Brisbane once observed DST prior (@Jon Skeet) to 1972, having daylight == 1 is reasonable as daylight implies DST was in effect for some periods of time for that timezone (likely since 1970).

OP's "... even though my time-zone does not use daylight savings at all" is not correct.


The following code shows that DST is used (at least the timezone DB thinks so) for some years since 1970 in "Australia/Brisbane".

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

int main(void) {
  setenv("TZ", "Australia/Brisbane", 1);
  tzset();
  time_t now;
  time(&now);
  struct tm tm;
  int isdst = 42; // See Hitchhiker's_Guide_to_the_Galaxy
  time_t t;
  for (t = 0; t < now; t += 3600) {
    tm = *localtime(&t);
    if (tm.tm_isdst != isdst) {
      printf("dst:%d %s", tm.tm_isdst, ctime(&t));
      isdst = tm.tm_isdst;
    }
  }
  printf("dst:%d %s", tm.tm_isdst, ctime(&t));
  return 0;
}

Output

dst:0 Thu Jan  1 10:00:00 1970
dst:1 Sun Oct 31 03:00:00 1971
dst:0 Sun Feb 27 02:00:00 1972
dst:1 Sun Oct 29 03:00:00 1989
dst:0 Sun Mar  4 02:00:00 1990
dst:1 Sun Oct 28 03:00:00 1990
dst:0 Sun Mar  3 02:00:00 1991
dst:1 Sun Oct 27 03:00:00 1991
dst:0 Sun Mar  1 02:00:00 1992
dst:0 Tue Dec  1 16:00:00 2015

Upvotes: 6

Jon Skeet
Jon Skeet

Reputation: 1502816

Australia/Brisbane doesn't use daylight saving time at the moment, but it has in the past; look at the australasia file you'll see the few years where it has observed DST.

My interpretation of daylight is that it indicates whether that time zone has ever observed (or will ever obseve with the current rules) daylight savings. In other words, if this is 1 you need to be careful when performing date/time handling, whereas if it's 0 you can assume a constant UTC offset.

(It's not immediately clear to me whether a time zone which has never observed DST, but has shifted its standard UTC offset over time, would set daylight to 1 or not. I guess it would be strictly wrong to set it, but it would be practical to do so for the reasons above...)

Upvotes: 3

Related Questions