Bug 1076801 - <time.h> functions incorrectly apply DST to system time even when it is not applicable.
Summary: <time.h> functions incorrectly apply DST to system time even when it is not a...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: rawhide
Hardware: All
OS: Linux
unspecified
medium
Target Milestone: ---
Assignee: Carlos O'Donell
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2014-03-15 09:07 UTC by pjp
Modified: 2016-11-24 12:40 UTC (History)
6 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2014-03-15 09:21:55 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
Reproducer for this bug. (972 bytes, text/x-c)
2014-03-15 09:07 UTC, pjp
no flags Details

Description pjp 2014-03-15 09:07:40 UTC
Created attachment 874737 [details]
Reproducer for this bug.

Description of problem:

When TZ environment variable is set to: 

    <standard-time-zone><[+-]timezone><dst-time-zone>
    TZ="IST-5:30IST"

<time.h> functions localtime(3), ctime(3), etc. incorrectly apply daylight saving time difference to the system time, even when DST does not apply to the current system time zone, ex: IST.

Version-Release number of selected component (if applicable):
glibc-2.17-20.fc19.x86_64

How reproducible: Always

Steps to Reproduce:
1. Download the reproducer
2. $ cc -xc -o dst dst.c
3. $ ./dst

Actual results:
===
  ...
  now: 15 Mar 2014 14:33:03 IST

  TZ set to: IST-5:30IST

  now: 15 Mar 2014 15:33:03 IST
===

Expected results:
===
  ...
  now: 15 Mar 2014 14:33:03 IST

  TZ set to: IST-5:30IST

  now: 15 Mar 2014 14:33:03 IST
===

Additional info:

  TZ="IST-5:30IST" should be treated as TZ="IST-5:30". Because IST does not follow daylight saving time. This applies to all time zones which do not follow DST.

Comment 1 Jakub Jelinek 2014-03-15 09:21:55 UTC
You are wrong, please read
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
carefully.
If you want the timezone database info about whether and when DST applies etc., you should use
TZ=Asia/Calcutta
or similar format, if you use the POSIX
stdoffset[dst[offset][,start[/time],end[/time]]]
format of TZ variable, then the name of the timezone is just a string without any special meaning (after all, multiple different timezones often use the same abbreviation), and the rules for the zone then follow exactly what you specify.
So, if you say TZ=IST-5:30 , then no dst is in effect, while if you say TZ=IST-5:30IST , then there is dst in effect and is one hour off from the std offset.

Comment 2 pjp 2014-03-15 11:45:35 UTC
  Hello Jakub,

(In reply to Jakub Jelinek from comment #1)
> You are wrong, please read
> http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
> carefully.

  That page says

 "...if dst is missing, then the alternative time does not apply in this locale"

But does not say how DST is processed if & when it is present. For a test I set

  TZ="QQQQ-5:30QQQ"

And it still applies the one hour of DST offset.

===
$ ./ dst
  ...
  now: 15 Mar 2014 16:49:54 IST

  TZ set to: QQQQ-5:30QQQ

  now: 15 Mar 2014 17:49:54 QQQ
===

It does not even consider if 'int daylight' variable is zero or a positive integer. Which is suppose to be an indication of whether DST rules apply or not. IMO, this implementation could use some work.

> If you want the timezone database info about whether and when DST applies
> etc., you should use
> TZ=Asia/Calcutta

  Is there a standard way to query such time zone name programatically?

I need to set TZ to the systems' current time zone value. So that a program running inside chroot(2) jail can use 'correct' timestamps, without having to do DST adjustments.

Thank you.

Comment 3 Jakub Jelinek 2014-03-15 12:59:32 UTC
But in your case
stdoffset[dst[offset][,start[/time],end[/time]]]
dst is not missing, it is present, you just haven't provided offset for it, so:
"If no offset follows dst, the alternative time is assumed to be one hour ahead of standard time."
then applies.
If you want timezone without DST, you would do: TZ=QQQQ-5:30

If you want to query what your timezone (usually set up during distro install) is, just ls -l /etc/localtime .

Comment 4 pjp 2014-03-15 13:41:06 UTC
(In reply to Jakub Jelinek from comment #3)
> But in your case
> dst is not missing, it is present, you just haven't provided offset for it,
> so:
> "If no offset follows dst, the alternative time is assumed to be one hour
> ahead of standard time."
> then applies.

  Yes, true. Yet, it is not expected that 1 hour offset would be applied blindly in time zones which do not follow DST at all, ever.

> If you want to query what your timezone (usually set up during distro
> install) is, just ls -l /etc/localtime .

  That is not programatically.

Anyway, for now I'm depending on value of 'int daylight' variable to set the TZ variable

  If (daylight > 0)
      TZ="STD<[+-]timezone>DST";
  else
      TZ="STD<[+-]timezone>"

Though I wonder if it is reliable. Suddenly on my local machine 'daylight' appears to be always set, irrespective of whether the current time zone uses DST or not.

===
$
$ cat t.c

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

int
main (int argc, char *argv[])
{
    printf ("daylight: %d\n", daylight);

    tzset();
    printf ("tz[0]: %s, tz[1]: %s, daylight: %d\n",
                        tzname[0], tzname[1], daylight);
    return 0;
}
$
$ ls -l /etc/localtime 
lrwxrwxrwx. 1 root root 32 Mar 15 18:52 /etc/localtime -> /usr/share/zoneinfo/Asia/Kolkata
$
$ date '+%T %Z %z'
19:05:02 IST +0530
$ 
$ ./t
daylight: 0
tz[0]: IST, tz[1]: IST, daylight: 1
$
$
===

Comment 5 pjp 2014-03-17 12:40:03 UTC
update_vars() function[1] appears to set 'daylight' when std_offset != dst_offset

  __daylight = tz_rules[0].offset != tz_rules[1].offset;

Is that correct?

That explains why I see 'daylight = 1' for IST. Because for IST it'll look like daylight = -5:30 != 00:00  or if it defaults to 1, that'll be -5:30 != 01:00.

Another test I did was, calling localtime(3) instead of tzset(3) or before tzset(3) shows daylight as 0.

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

int
main (int argc, char *argv[])
{
    time_t t;
    printf ("daylight: %d\n", daylight);

    t = time (NULL);
    localtime(&t);

    tzset();
    printf ("tz[0]: %s, tz[1]: %s, daylight: %d\n",
                        tzname[0], tzname[1], daylight);
    return 0;
}
$ cc -xc -o t t.c
$
$ ./t
daylight: 0
tz[0]: IST, tz[1]: IST, daylight: 0
===


[1] -> https://sourceware.org/git/?p=glibc.git;a=blob;f=time/tzset.c;h=77bfde9fb1f3595a0ad4536a3fa03684474bf148;hb=HEAD#l140

Comment 6 Carlos O'Donell 2014-03-17 16:49:08 UTC
(In reply to pjp from comment #4)
> (In reply to Jakub Jelinek from comment #3)
> > But in your case
> > dst is not missing, it is present, you just haven't provided offset for it,
> > so:
> > "If no offset follows dst, the alternative time is assumed to be one hour
> > ahead of standard time."
> > then applies.
> 
>   Yes, true. Yet, it is not expected that 1 hour offset would be applied
> blindly in time zones which do not follow DST at all, ever.

I agree, but as Jakub points out, and I didn't think of this, other geographical zones might use IST and still apply daylight savings, thus IST-5:30IST could be used for such a zone following POSIX rules.

> > If you want to query what your timezone (usually set up during distro
> > install) is, just ls -l /etc/localtime .
> 
>   That is not programatically.

Use localtime and examine the broken-down time to see if daylight savings is in effect for the current time? You will have problems as you transition from daylight in effect to not in effect. It's looking like the only solution is to modify the chroot's /etc/localtime to match the server before starting any process within it or setting TZ=:<file> to match the servers e.g. TZ=:India/Calcutta (no leading / makes it relative to installed zoninfo directory).

> Anyway, for now I'm depending on value of 'int daylight' variable to set the
> TZ variable
> 
>   If (daylight > 0)
>       TZ="STD<[+-]timezone>DST";
>   else
>       TZ="STD<[+-]timezone>"

You can't do this. We talked about this on IRC. The `daylight' variable indicates that the tz *may* have dalyight savings applied at some point, but doesn't tell you when.

> Though I wonder if it is reliable. Suddenly on my local machine 'daylight'
> appears to be always set, irrespective of whether the current time zone uses
> DST or not.

Daylight should only be set initially if your tz uses it at some point during the year.

> ===
> $
> $ cat t.c
> 
> #include <time.h>
> #include <stdio.h>
> 
> int
> main (int argc, char *argv[])
> {
>     printf ("daylight: %d\n", daylight);
> 
>     tzset();
>     printf ("tz[0]: %s, tz[1]: %s, daylight: %d\n",
>                         tzname[0], tzname[1], daylight);
>     return 0;
> }
> $
> $ ls -l /etc/localtime 
> lrwxrwxrwx. 1 root root 32 Mar 15 18:52 /etc/localtime ->
> /usr/share/zoneinfo/Asia/Kolkata
> $
> $ date '+%T %Z %z'
> 19:05:02 IST +0530
> $ 
> $ ./t
> daylight: 0

This is garbage, you can't rely on daylight until you call tzset().

> tz[0]: IST, tz[1]: IST, daylight: 1

This is a bug. Kolkota should not have daylight set if you started from a known zoneinfo for Asia/Kolkata.

Comment 7 Carlos O'Donell 2014-03-17 16:54:25 UTC
(In reply to pjp from comment #5)
> update_vars() function[1] appears to set 'daylight' when std_offset !=
> dst_offset
> 
>   __daylight = tz_rules[0].offset != tz_rules[1].offset;
> 
> Is that correct?

Maybe. It depends on other logic and the timezone setting.

> That explains why I see 'daylight = 1' for IST. Because for IST it'll look
> like daylight = -5:30 != 00:00  or if it defaults to 1, that'll be -5:30 !=
> 01:00.

You haven't provided enough information for me to agree. I don't know what you ran to get your observed result.

> Another test I did was, calling localtime(3) instead of tzset(3) or before
> tzset(3) shows daylight as 0.
> 
> ===
> #include <time.h>
> #include <stdio.h>
> 
> int
> main (int argc, char *argv[])
> {
>     time_t t;
>     printf ("daylight: %d\n", daylight);

This again is invalid, you can't read daylight before calling a time function.

>     t = time (NULL);
>     localtime(&t);

This parses the time.

>     tzset();
>     printf ("tz[0]: %s, tz[1]: %s, daylight: %d\n",
>                         tzname[0], tzname[1], daylight);

For Asia/Kolkata this should have:

tz[0]: IST, tz[1]:, daylight 0

>     return 0;
> }
> $ cc -xc -o t t.c
> $
> $ ./t
> daylight: 0
> tz[0]: IST, tz[1]: IST, daylight: 0

Interesting, I expected tz[1] to be empty. That's a bug IMO. Since the glibc manual specifically says:
"If Daylight Saving Time is never used, tzname[1] is the empty string."

So I would expect tz[1] to be empty.

Comment 8 Jakub Jelinek 2014-03-17 17:13:19 UTC
(In reply to Carlos O'Donell from comment #6)
> >   If (daylight > 0)
> >       TZ="STD<[+-]timezone>DST";
> >   else
> >       TZ="STD<[+-]timezone>"
> 
> You can't do this. We talked about this on IRC. The `daylight' variable
> indicates that the tz *may* have dalyight savings applied at some point, but
> doesn't tell you when.

I believe POSIX mandates that if the start[/time],end[/time] part is missing (i.e. you specify explicitly in the TZ variable when the STD to DST and DST to STD change happen), then the US DST changing dates apply, i.e.
M3.2.0,M11.1.0
(second Sunday in March, first SUnday in October, both at 2am).

Comment 9 pjp 2014-03-17 17:40:37 UTC
(In reply to Carlos O'Donell from comment #6)
> You can't do this. We talked about this on IRC. The `daylight' variable
> indicates that the tz *may* have dalyight savings applied at some point, but
> doesn't tell you when.

  True. tzset(3) manual says

  "...daylight (to 0 if this timezone does not have any  daylight
   saving  time  rules,  or  to nonzero if there is a time during the year
   when daylight saving time applies)"

So 'daylight' should only be set if at all the current system time-zone follows DST sometime during the year. That is why I used it, assuming it won't be set for time-zones like IST(Indian Standard Time), as discussed on IRC,

===
...
<pjp> codonell: It adds an extra hour in case of 'IST-5:30IST',  though IST does not have DST
<codonell> pjp: Leave off IST at the end.
<codonell> pjp: Does that work?
<codonell> pjp: So you're saying IST-5:30IST seems to apply a DST adjustment?
<pjp> codonell: Yes.
<pjp> codonell: leaving off the IST at the end does work.
...
===

> > $ ./t
> > daylight: 0
> This is garbage, you can't rely on daylight until you call tzset().

  Yes, I was using 'daylight' only after calling tzset(3).
 
> This is a bug. Kolkota should not have daylight set if you started from a
> known zoneinfo for Asia/Kolkata.

  Right. Should I file another bug for this or re-open this one?


I'll try broken-down structure returned by localtime(3) to see how DST could be applied reliably. Thanks so much.

Thank you.

Comment 10 pjp 2014-03-17 17:44:58 UTC
(In reply to Carlos O'Donell from comment #7)
> > That explains why I see 'daylight = 1' for IST. Because for IST it'll look
> > like daylight = -5:30 != 00:00  or if it defaults to 1, that'll be -5:30 !=
> > 01:00.
> You haven't provided enough information for me to agree. I don't know what
> you ran to get your observed result.

  No, that was an inference from how update_vars() sets __daylight variable. It is comparing STD offset and DST offset for non-equality, right?

Comment 11 Carlos O'Donell 2014-03-17 18:25:08 UTC
(In reply to pjp from comment #9)
> (In reply to Carlos O'Donell from comment #6)
> > You can't do this. We talked about this on IRC. The `daylight' variable
> > indicates that the tz *may* have dalyight savings applied at some point, but
> > doesn't tell you when.
> 
>   True. tzset(3) manual says
> 
>   "...daylight (to 0 if this timezone does not have any  daylight
>    saving  time  rules,  or  to nonzero if there is a time during the year
>    when daylight saving time applies)"
> 
> So 'daylight' should only be set if at all the current system time-zone
> follows DST sometime during the year. That is why I used it, assuming it
> won't be set for time-zones like IST(Indian Standard Time), as discussed on
> IRC,

Unfortunately I was wrong.

It turns out glibc does not associate any rules with IST, only that it's a timezone with an offset from GMT/UTC. It seems perhaps an enhancement to add a default IST zone to tzdata with zoneinfo like EST is handled. Note that EDT is not actually specified as a zone so it also has no rules, using TZ=EDT results in GMT time being used.
 
> ===
> ...
> <pjp> codonell: It adds an extra hour in case of 'IST-5:30IST',  though IST
> does not have DST
> <codonell> pjp: Leave off IST at the end.
> <codonell> pjp: Does that work?
> <codonell> pjp: So you're saying IST-5:30IST seems to apply a DST adjustment?
> <pjp> codonell: Yes.
> <pjp> codonell: leaving off the IST at the end does work.
> ...
> ===

Yes, this follows the rules as described in POSIX as pointed out by Jakub (I missed that line). That IST-5:30IST will result in a fixed 1 hour DST offset likely following some default dates for transition (I could find no such dates in POSIX Issue 7, but glibc probably defaults to somethings).

> > > $ ./t
> > > daylight: 0
> > This is garbage, you can't rely on daylight until you call tzset().
> 
>   Yes, I was using 'daylight' only after calling tzset(3).

OK.
  
> > This is a bug. Kolkota should not have daylight set if you started from a
> > known zoneinfo for Asia/Kolkata.
> 
>   Right. Should I file another bug for this or re-open this one?
 
Let us keep it clean. File another bug and we'll fix that, and in this case the bug is against tzdata I believe as we're just consuming the data from that package.
 
> I'll try broken-down structure returned by localtime(3) to see how DST could
> be applied reliably. Thanks so much.

It would seem that you must rely on distribution specific information to set TZ=:<file> to solve this problem completely and easily. Why? Specifying TZ=:<file> requires knowing which <file> was used by the server (distribution specific information). Specifying e.g. TZ="EST+5EDT,M3.2.0/2,M11.1.0/2" (fully specified) is difficult since the only incoming information via any API is standard timezone, daylight timezone, is daylight in effect right now, is daylight ever in effect, and present timezone offset. One might argue that you could do some kind of binary search for the DST change dates and then fully specify TZ, that seems obtuse.

Comment 12 Jakub Jelinek 2014-03-17 18:40:25 UTC
(In reply to Carlos O'Donell from comment #11)
> It turns out glibc does not associate any rules with IST, only that it's a
> timezone with an offset from GMT/UTC. It seems perhaps an enhancement to add
> a default IST zone to tzdata with zoneinfo like EST is handled. Note that
> EDT is not actually specified as a zone so it also has no rules, using
> TZ=EDT results in GMT time being used.

But EST is ambiguous, it is used e.g. for America/New_York std, or e.g. Australia/Sydney std.
IST is ambiguous as well, it can be Asia/Kolkata, Asia/Jerusalem, Europe/Dublin, Asia/Dhaka, Asia/Thimphu, Asia/Kathmandu, Asia/Karachi, Asia/Colombo.

> It would seem that you must rely on distribution specific information to set
> TZ=:<file> to solve this problem completely and easily. Why? Specifying
> TZ=:<file> requires knowing which <file> was used by the server
> (distribution specific information). Specifying e.g.
> TZ="EST+5EDT,M3.2.0/2,M11.1.0/2" (fully specified) is difficult since the
> only incoming information via any API is standard timezone, daylight
> timezone, is daylight in effect right now, is daylight ever in effect, and
> present timezone offset. One might argue that you could do some kind of
> binary search for the DST change dates and then fully specify TZ, that seems
> obtuse.

Isn't that what
zdump -v Asia/Kolkata
performs?
In any case, in the current timezone data file format, there is a POSIX TZ string for the latest rule if it is possible to express the transitions in the POSIX TZ env var format.
Say, if you look at end of /usr/share/zoneinfo/Asia/Kolkata, there is
IST-5:30
/usr/share/zoneinfo/America/New_York ends with
EST5EDT,M3.2.0,M11.1.0
or say /usr/share/zoneinfo/Europe/Prague ends with
CET-1CEST,M3.5.0,M10.5.0/3

Comment 13 Carlos O'Donell 2014-03-17 19:06:49 UTC
(In reply to Jakub Jelinek from comment #12)
> (In reply to Carlos O'Donell from comment #11)
> > It turns out glibc does not associate any rules with IST, only that it's a
> > timezone with an offset from GMT/UTC. It seems perhaps an enhancement to add
> > a default IST zone to tzdata with zoneinfo like EST is handled. Note that
> > EDT is not actually specified as a zone so it also has no rules, using
> > TZ=EDT results in GMT time being used.
> 
> But EST is ambiguous, it is used e.g. for America/New_York std, or e.g.
> Australia/Sydney std.

EST is ambiguous but regardless of that tzdata has a default zone for it with default rules (I assume POSIX rules which are effectively America/New_York). One could equally decide IST is Indian Standard Time as the default and every other IST has to use another unique zone file by name. However, the comments in tzdata indicate EST is a zone for historical purposes to remove any older EST file that might have been there.

I retract my suggestion then to add a default IST since it seems tzdata really wants us to use Area/City instead.

> IST is ambiguous as well, it can be Asia/Kolkata, Asia/Jerusalem,
> Europe/Dublin, Asia/Dhaka, Asia/Thimphu, Asia/Kathmandu, Asia/Karachi,
> Asia/Colombo.

You are correct. I didn't mention that, but it's either Irish Summer Time or Israel Standard time. Which is why glibc can't determine what rules apply without tzdata choosing a default.

Either way after reading the zdata souce I see this is a bad idea.
 
> > It would seem that you must rely on distribution specific information to set
> > TZ=:<file> to solve this problem completely and easily. Why? Specifying
> > TZ=:<file> requires knowing which <file> was used by the server
> > (distribution specific information). Specifying e.g.
> > TZ="EST+5EDT,M3.2.0/2,M11.1.0/2" (fully specified) is difficult since the
> > only incoming information via any API is standard timezone, daylight
> > timezone, is daylight in effect right now, is daylight ever in effect, and
> > present timezone offset. One might argue that you could do some kind of
> > binary search for the DST change dates and then fully specify TZ, that seems
> > obtuse.
> 
> Isn't that what
> zdump -v Asia/Kolkata
> performs?

How do you know you're in Asia/Kolkata?

You must know your distribution to know which file to run zdump -v on.

> In any case, in the current timezone data file format, there is a POSIX TZ
> string for the latest rule if it is possible to express the transitions in
> the POSIX TZ env var format.
> Say, if you look at end of /usr/share/zoneinfo/Asia/Kolkata, there is
> IST-5:30
> /usr/share/zoneinfo/America/New_York ends with
> EST5EDT,M3.2.0,M11.1.0
> or say /usr/share/zoneinfo/Europe/Prague ends with
> CET-1CEST,M3.5.0,M10.5.0/3

That looks like an undocumented field AFAICT that zic writes out at the end of the file. I would not like to rely on this being here always. Though it would be nice of zdump -v printed it. So perhaps there is an enhancement to be made to tzdump.

Comment 14 pjp 2014-03-17 19:15:36 UTC
> Let us keep it clean. File another bug and we'll fix that, and in this case
> the bug is against tzdata I believe as we're just consuming the data from
> that package.

  Okay. But I don't think bug is in tzdata, because localtime(3) does set the 'daylight' & 'tm_isdst' values correctly. IIUC, it is tzset(3) at fault.

Comment 15 pjp 2014-03-17 19:24:55 UTC
> > In any case, in the current timezone data file format, there is a POSIX TZ
> > string for the latest rule if it is possible to express the transitions in
> > the POSIX TZ env var format.
> > Say, if you look at end of /usr/share/zoneinfo/Asia/Kolkata, there is
> > IST-5:30
> > /usr/share/zoneinfo/America/New_York ends with
> > EST5EDT,M3.2.0,M11.1.0
> > or say /usr/share/zoneinfo/Europe/Prague ends with
> > CET-1CEST,M3.5.0,M10.5.0/3
> 
> That looks like an undocumented field AFAICT that zic writes out at the end
> of the file. I would not like to rely on this being here always. Though it
> would be nice of zdump -v printed it. So perhaps there is an enhancement to
> be made to tzdump.

  IIUC, tzdata files like Asia/Kolkata, Canada/Easter, or Ameria/New_York etc. do provide all the necessary information about the time-zone. Including when and how DST applies, if at all it applies.

  <time.h> functions appear to read the same binary files to know the time-zone details. But there seems to be a bug in how these functions interpret & use that information while applying POSIX rules.

Anyway, I used localtime(3) and the 'tm_isdst' field from the 'struct tm' structure. It seems to be reliable, for it is always 0 for IST, and shows positive values for other time-zones like EST. I'm using 

+     snprintf (tzone, sizeof (tzone), "%s%+02d:%02d:%02d%s",
+                tzname[0], hh, mm, ss, (tt->tm_isdst > 0) ? tzname[1] : "");

Hope it is okay.

Please let me know if I should file another bug for tzset(3), I'll do that once you confirm.

Thank you.

Comment 16 Carlos O'Donell 2014-03-17 19:25:43 UTC
(In reply to Carlos O'Donell from comment #13)
> > In any case, in the current timezone data file format, there is a POSIX TZ
> > string for the latest rule if it is possible to express the transitions in
> > the POSIX TZ env var format.
> > Say, if you look at end of /usr/share/zoneinfo/Asia/Kolkata, there is
> > IST-5:30
> > /usr/share/zoneinfo/America/New_York ends with
> > EST5EDT,M3.2.0,M11.1.0
> > or say /usr/share/zoneinfo/Europe/Prague ends with
> > CET-1CEST,M3.5.0,M10.5.0/3
> 
> That looks like an undocumented field AFAICT that zic writes out at the end
> of the file. I would not like to rely on this being here always. Though it
> would be nice of zdump -v printed it. So perhaps there is an enhancement to
> be made to tzdump.

OK, it *is* documented, I missed it:
For  version-2-format  timezone  files,  the above header and data is followed by a second header and data, identical in format except that eight bytes are used for each transition time or leap-second time.  After the second header and data comes  a  newline-enclosed,  POSIX-TZ-environment-variable-style  string for use in handling instants after the last transition time stored in the file (with nothing between the newlines if there is no POSIX representation for such instants).

It would still be nice if this was dumped.

Comment 17 Carlos O'Donell 2014-03-17 19:26:33 UTC
(In reply to pjp from comment #14)
> > Let us keep it clean. File another bug and we'll fix that, and in this case
> > the bug is against tzdata I believe as we're just consuming the data from
> > that package.
> 
>   Okay. But I don't think bug is in tzdata, because localtime(3) does set
> the 'daylight' & 'tm_isdst' values correctly. IIUC, it is tzset(3) at fault.

OK, in that case file a bug against glibc and tzset with the test case.

Comment 18 Carlos O'Donell 2014-03-17 19:33:08 UTC
(In reply to pjp from comment #15)
> > > In any case, in the current timezone data file format, there is a POSIX TZ
> > > string for the latest rule if it is possible to express the transitions in
> > > the POSIX TZ env var format.
> > > Say, if you look at end of /usr/share/zoneinfo/Asia/Kolkata, there is
> > > IST-5:30
> > > /usr/share/zoneinfo/America/New_York ends with
> > > EST5EDT,M3.2.0,M11.1.0
> > > or say /usr/share/zoneinfo/Europe/Prague ends with
> > > CET-1CEST,M3.5.0,M10.5.0/3
> > 
> > That looks like an undocumented field AFAICT that zic writes out at the end
> > of the file. I would not like to rely on this being here always. Though it
> > would be nice of zdump -v printed it. So perhaps there is an enhancement to
> > be made to tzdump.
> 
>   IIUC, tzdata files like Asia/Kolkata, Canada/Easter, or Ameria/New_York
> etc. do provide all the necessary information about the time-zone. Including
> when and how DST applies, if at all it applies.

That's expected.

>   <time.h> functions appear to read the same binary files to know the
> time-zone details. But there seems to be a bug in how these functions
> interpret & use that information while applying POSIX rules.

I'm not aware of any bugs except the one we just talked about with tzset.

> Anyway, I used localtime(3) and the 'tm_isdst' field from the 'struct tm'
> structure. It seems to be reliable, for it is always 0 for IST, and shows
> positive values for other time-zones like EST. I'm using 
> 
> +     snprintf (tzone, sizeof (tzone), "%s%+02d:%02d:%02d%s",
> +                tzname[0], hh, mm, ss, (tt->tm_isdst > 0) ? tzname[1] : "");
> 
> Hope it is okay.

That works, but the chroot'd environment will fail to transition DST at the right time. You've specified that a 1 hour DST is in effect or not in effect *right now*. You need the additional rules to let the system transition to and from DST e.g. EST5EDT,M3.2.0,M11.1.0 with the "M3.2.0,M11.1.0" being the rules i.e. ",start/time,end/time".

> Please let me know if I should file another bug for tzset(3), I'll do that
> once you confirm.

Please do. Please don't assume anything when you submit that bug, please include all the same information you'd have given someone new. I may hand this to another member of the glibc team for review.

Comment 19 pjp 2014-03-17 19:36:05 UTC
(In reply to pjp from comment #15)
> I used localtime(3) and the 'tm_isdst' field from the 'struct tm'
> structure. It seems to be reliable, for it is always 0 for IST, and shows
> positive values for other time-zones like EST.

  Sorry! Turns out even localtime(3) is failing for Israel Standard Time(IST), which does follow DST.

===
# ls -l /etc/localtime 
lrwxrwxrwx. 1 root root 34 Mar 17 21:26 /etc/localtime -> /usr/share/zoneinfo/Asia/Jerusalem
# 
# date '+%Z %z'
IST +0200
#
# cat t.c

#include <time.h>                                                               
#include <stdio.h>                                                              
                                                                                
int                                                                             
main (int argc, char *argv[])                                                   
{                                                                               
    time_t t = 0;
    struct tm *tt = NULL;

    printf ("daylight: %d\n", daylight);                                        
                                                                                
    t = time (NULL);
    tt = localtime (&t);

    printf ("tz[0]: %s, tz[1]: %s, daylight: %d\n",
                        tzname[0], tzname[1], tt->tm_isdst);       
    return 0;                                                             
}
#
# cc -xc -o t t.c
# 
# ./t
daylight: 0
tz[0]: IST, tz[1]: IDT, daylight: 0
===

Comment 20 pjp 2014-03-17 19:40:52 UTC
(In reply to Carlos O'Donell from comment #18)
> I'm not aware of any bugs except the one we just talked about with tzset.

  Yes, same one.
 
> That works, but the chroot'd environment will fail to transition DST at the
> right time. You've specified that a 1 hour DST is in effect or not in effect
> *right now*. You need the additional rules to let the system transition to
> and from DST e.g. EST5EDT,M3.2.0,M11.1.0 with the "M3.2.0,M11.1.0" being the
> rules i.e. ",start/time,end/time".

  Ah right, true. But for that, there must be an API that would read the tzdata files and return the time-zone string value. Then a caller could use that verbatim to export to the environment as TZ.
 
> Please do. Please don't assume anything when you submit that bug, please
> include all the same information you'd have given someone new. I may hand
> this to another member of the glibc team for review.

  Right, I'll do that.

Comment 21 pjp 2014-03-17 19:48:20 UTC
(In reply to pjp from comment #19)
>   Sorry! Turns out even localtime(3) is failing for Israel Standard
> Time(IST), which does follow DST.

  Sorry. This could be because Israel follow DST from Mar 28 - Oct 26. [1]

Israel	All locations	Jerusalem	Friday, 28 March     Sunday, 26 October
--
[1] -> http://www.timeanddate.com/time/dst/2014.html

Comment 22 pjp 2014-03-17 20:32:43 UTC
(In reply to pjp from comment #20)
> > Please do. Please don't assume anything when you submit that bug, please
> > include all the same information you'd have given someone new. I may hand
> > this to another member of the glibc team for review.
> 
>   Right, I'll do that.

  Done -> https://bugzilla.redhat.com/show_bug.cgi?id=1077377

Thank you.


Note You need to log in before you can comment on or make changes to this bug.