<div dir="ltr">Here are possible changes to australasia, localtime.c, and zic.c<br>to deal with Macquarie.<br><br>Below, &quot;current&quot; means what&#39;s in tzcode2013c and tzdata2013c<br>(and the results of a &quot;make&quot; on those files).<br>
<br>australasia is changed so that if it&#39;s run through current (and earlier)<br>versions of zic they&#39;ll produce a binary file that give correct results<br>when processed by current (and earlier) versions of localtime.c<br>
<br>localtime.c is changed to give correct results when processing the current<br>binary Antarctica/Macquarie file.<br>I&#39;ve compiled zdump using this version of localtime.c and done a &quot;zdump -v&quot;<br>on all the binary files produced by default, using the command<br>
     cd /top/of/zoneinfo/binary/tree ; zdump -v `find * -type f -print`<br>and compared the results with those produced by compiling zdump with<br>the current localtime.c; other than for pre-1916 Macquarie times, all<br>results are the same.<br>
<br>zic.c is changed so that it produces a binary file from the current<br>australasia that the current localtime.c handles correctly.<br>The changes are bulkier than strictly necessary so that the only<br>change to output is for the Antarctica/Macquarie file; I&#39;ve done<br>
the relevant &quot;diff -r&quot; to verify that no other binary output changes.<br>(Basically, the zic changes arrange for Macquarie&#39;s &quot;EST&quot; type to appear first<br>in the 32-bit portion of the binary output; since the current localtime<br>
uses the first standard-time type for early times, the reordering<br>induces correct behavior.)<br><br>(The unique-in-the-existing-data aspect of Macquarie: it was &quot;zzz&quot; before 1899,<br>which falls outside the 32-bit time_t window, and re-entered &quot;zzz&quot; in 1948<br>
which is within that&#39;s within the 32-bit window.)<br><br>diff output is attached and also appear below (with tabs manged).<br><br>A long-term possibility is to change zic to always output<br>pseudo-transition-time data for the lowest possible time_t value;<br>
since doing that would change every binary file I did avoided that<br>approach today.<br><br>And...all this was done in a 32-bit environment; regression testing in<br>a 64-bit environment is prudent.<br><br>    @dashdashado<br>
<br>*** /tmp/,aaustralasia    2013-05-23 19:44:48.910652000 +0300<br>--- /tmp/,baustralasia    2013-05-23 19:44:49.097852300 +0300<br>***************<br>*** 230,239 ****<br>  # - Macquarie Island will stay on UTC+11 for winter and therefore not<br>
  # switch back from daylight savings time when other parts of Australia do<br>  # on 4 April.<br>  Zone Antarctica/Macquarie 0    -    zzz    1899 Nov<br>              10:00    -    EST    1916 Oct 1 2:00<br>              10:00    1:00    EST    1917 Feb<br>
!             10:00    Aus    EST    1919 Apr<br>              0    -    zzz    1948 Mar 25<br>              10:00    Aus    EST    1967<br>              10:00    AT    EST    2010 Apr 4 3:00<br>--- 230,245 ----<br>  # - Macquarie Island will stay on UTC+11 for winter and therefore not<br>
  # switch back from daylight savings time when other parts of Australia do<br>  # on 4 April.<br>+ #<br>+ # From Arthur David Olson (2013-05-23):<br>+ # The 1919 transition is overspecified below so pre-2013 zics<br>+ # will produce a binary file with an EST-type as the first 32-bit type;<br>
+ # this is required for correct handling of times before 1916 by<br>+ # pre-2013 versions of localtime.<br>  Zone Antarctica/Macquarie 0    -    zzz    1899 Nov<br>              10:00    -    EST    1916 Oct 1 2:00<br>              10:00    1:00    EST    1917 Feb<br>
!             10:00    Aus    EST    1919 Apr 1 0:00s<br>              0    -    zzz    1948 Mar 25<br>              10:00    Aus    EST    1967<br>              10:00    AT    EST    2010 Apr 4 3:00<br>*** /tmp/,alocaltime.c    2013-05-23 19:44:49.285052600 +0300<br>
--- /tmp/,blocaltime.c    2013-05-23 19:44:49.363052800 +0300<br>***************<br>*** 112,117 ****<br>--- 112,118 ----<br>      char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),<br>                  (2 * (MY_TZNAME_MAX + 1)))];<br>
      struct lsinfo    lsis[TZ_MAX_LEAPS];<br>+     int        defaulttype;    /* for early times or if no transitions */<br>  };<br>  <br>  struct rule {<br>***************<br>*** 582,587 ****<br>--- 583,622 ----<br>                      break;<br>
          }<br>      }<br>+     /*<br>+     ** If type 0 is is unused in transitions,<br>+     ** it&#39;s the type to use for early times.<br>+     */<br>+     for (i = 0; i &lt; sp-&gt;typecnt; ++i)<br>+         if (sp-&gt;types[i] == 0)<br>
+             break;<br>+     i = (i &gt;= sp-&gt;typecnt) ? 0 : -1;<br>+     /*<br>+     ** Absent the above,<br>+     ** if there are transition times<br>+     ** and the first transition is to a daylight time<br>+     ** find the standard type less than and closest to<br>
+     ** the type of the first transition.<br>+     */<br>+     if (i &lt; 0 &amp;&amp; sp-&gt;timecnt &gt; 0 &amp;&amp; sp-&gt;ttis[sp-&gt;types[0]].tt_isdst) {<br>+         i = sp-&gt;types[0];<br>+         while (--i &gt;= 0)<br>
+             if (!sp-&gt;ttis[i].tt_isdst)<br>+                 break;<br>+     }<br>+     /*<br>+     ** If no result yet, find the first standard type.<br>+     ** If there is none, punt to type zero.<br>+     */<br>+     if (i &lt; 0) {<br>
+         i = 0;<br>+         while (sp-&gt;ttis[i].tt_isdst)<br>+             if (++i &gt;= sp-&gt;typecnt) {<br>+                 i = 0;<br>+                 break;<br>+             }<br>+     }<br>+     sp-&gt;defaulttype = i;<br>
  #ifdef ALL_STATE<br>      free(up);<br>  #endif /* defined ALL_STATE */<br>***************<br>*** 1283,1294 ****<br>              return result;<br>      }<br>      if (sp-&gt;timecnt == 0 || t &lt; sp-&gt;ats[0]) {<br>
!         i = 0;<br>!         while (sp-&gt;ttis[i].tt_isdst)<br>!             if (++i &gt;= sp-&gt;typecnt) {<br>!                 i = 0;<br>!                 break;<br>!             }<br>      } else {<br>          register int    lo = 1;<br>
          register int    hi = sp-&gt;timecnt;<br>--- 1318,1324 ----<br>              return result;<br>      }<br>      if (sp-&gt;timecnt == 0 || t &lt; sp-&gt;ats[0]) {<br>!         i = sp-&gt;defaulttype;<br>      } else {<br>
          register int    lo = 1;<br>          register int    hi = sp-&gt;timecnt;<br>*** /tmp/,azic.c    2013-05-23 19:44:49.550253100 +0300<br>--- /tmp/,bzic.c    2013-05-23 19:44:49.643853300 +0300<br>***************<br>
*** 1414,1421 ****<br>          fromi = 0;<br>          while (fromi &lt; timecnt &amp;&amp; attypes[fromi].at &lt; min_time)<br>              ++fromi;<br>!         if (isdsts[0] == 0)<br>!             while (fromi &lt; timecnt &amp;&amp; attypes[fromi].type == 0)<br>
                  ++fromi;    /* handled by default rule */<br>          for ( ; fromi &lt; timecnt; ++fromi) {<br>              if (toi != 0 &amp;&amp; ((attypes[fromi].at +<br>--- 1414,1424 ----<br>          fromi = 0;<br>
          while (fromi &lt; timecnt &amp;&amp; attypes[fromi].at &lt; min_time)<br>              ++fromi;<br>!         /*<br>!         ** Remember that type 0 is reserved.<br>!         */<br>!         if (isdsts[1] == 0)<br>
!             while (fromi &lt; timecnt &amp;&amp; attypes[fromi].type == 1)<br>                  ++fromi;    /* handled by default rule */<br>          for ( ; fromi &lt; timecnt; ++fromi) {<br>              if (toi != 0 &amp;&amp; ((attypes[fromi].at +<br>
***************<br>*** 1517,1523 ****<br>          }<br>          thistimelim = thistimei + thistimecnt;<br>          thisleaplim = thisleapi + thisleapcnt;<br>!         for (i = 0; i &lt; typecnt; ++i)<br>              writetype[i] = thistimecnt == timecnt;<br>
          if (thistimecnt == 0) {<br>              /*<br>--- 1520,1530 ----<br>          }<br>          thistimelim = thistimei + thistimecnt;<br>          thisleaplim = thisleapi + thisleapcnt;<br>!         /*<br>!         ** Remember that type 0 is reserved.<br>
!         */<br>!         writetype[0] = FALSE;<br>!         for (i = 1; i &lt; typecnt; ++i)<br>              writetype[i] = thistimecnt == timecnt;<br>          if (thistimecnt == 0) {<br>              /*<br>***************<br>
*** 1533,1540 ****<br>              /*<br>              ** For America/Godthab and Antarctica/Palmer<br>              */<br>              if (thistimei == 0)<br>!                 writetype[0] = TRUE;<br>          }<br>  #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH<br>
          /*<br>--- 1540,1550 ----<br>              /*<br>              ** For America/Godthab and Antarctica/Palmer<br>              */<br>+             /*<br>+             ** Remember that type 0 is reserved.<br>+             */<br>
              if (thistimei == 0)<br>!                 writetype[1] = TRUE;<br>          }<br>  #ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH<br>          /*<br>***************<br>*** 1584,1591 ****<br>          }<br>  #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */<br>
          thistypecnt = 0;<br>          for (i = 0; i &lt; typecnt; ++i)<br>!             typemap[i] = writetype[i] ?  thistypecnt++ : -1;<br>          for (i = 0; i &lt; sizeof indmap / sizeof indmap[0]; ++i)<br>              indmap[i] = -1;<br>
          thischarcnt = 0;<br>--- 1594,1619 ----<br>          }<br>  #endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */<br>          thistypecnt = 0;<br>+         /*<br>+         ** Potentially, set type 0 to that of lowest-valued time.<br>
+         */<br>+         if (thistimei &gt; 0) {<br>+             for (i = 1; i &lt; typecnt; ++i)<br>+                 if (writetype[i] &amp;&amp; !isdsts[i])<br>+                     break;<br>+             if (i != types[thistimei - 1]) {<br>
+                 i = types[thistimei - 1];<br>+                 gmtoffs[0] = gmtoffs[i];<br>+                 isdsts[0] = isdsts[i];<br>+                 ttisstds[0] = ttisstds[i];<br>+                 ttisgmts[0] = ttisgmts[i];<br>
+                 abbrinds[0] = abbrinds[i];<br>+                 writetype[0] = TRUE;<br>+                 writetype[i] = FALSE;<br>+             }<br>+         }<br>          for (i = 0; i &lt; typecnt; ++i)<br>!             typemap[i] = writetype[i] ?  thistypecnt++ : 0;<br>
          for (i = 0; i &lt; sizeof indmap / sizeof indmap[0]; ++i)<br>              indmap[i] = -1;<br>          thischarcnt = 0;<br>***************<br>*** 1942,1947 ****<br>--- 1970,1980 ----<br>          updateminmax(leapminyear);<br>
          updateminmax(leapmaxyear + (leapmaxyear &lt; INT_MAX));<br>      }<br>+     /*<br>+     ** Reserve type 0.<br>+     */<br>+     gmtoffs[0] = isdsts[0] = ttisstds[0] = ttisgmts[0] = abbrinds[0] = -1;<br>+     typecnt = 1;<br>
      for (i = 0; i &lt; zonecount; ++i) {<br>          zp = &amp;zpfirst[i];<br>          if (i &lt; zonecount - 1)<br><br></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, May 22, 2013 at 10:21 PM, Alan Gutierrez <span dir="ltr">&lt;<a href="mailto:alan@prettyrobots.com" target="_blank">alan@prettyrobots.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I&#39;m compiling the TZ database using the using the `zic` from the source<br>
distributed with the database checked out from GitHub. I&#39;m using the commit that<br>
relates to the `tz2013c` release. I&#39;m not able to get an Australian EST timezone<br>
offset for dates before October 1916 for Antarctica/Macquarie.<br>
<br>
I&#39;m using both Ruby 1.9.3p392 and GNU date 8.15.<br>
<br>
When I compile the TZ database at commit 188b29d966; &quot;Fix times of habitation<br>
for Macquarie to agree with Tasmania history&quot; I get the unhabited offset and<br>
abbreviation.<br>
<br>
% TZ=&quot;$PWD/build/zoneinfo/<u></u>Antarctica/Macquarie&quot; date -d &quot;1916/09/30 16:00 UTC&quot;<br>
Sun Oct  1 03:00:00 EST 1916<br>
% TZ=&quot;$PWD/build/zoneinfo/<u></u>Antarctica/Macquarie&quot; date -d &quot;1916/09/30 15:59 UTC&quot;<br>
Sat Sep 30 15:59:00 zzz 1916<br>
<br>
When I compile the TZ database at commit a676f5ad3b; &quot;Macquarie Island is<br>
politically part of Australia, not Antarctica&quot; I get the correct offset and<br>
abbreviation.<br>
<br>
% TZ=&quot;$PWD/build/zoneinfo/<u></u>Antarctica/Macquarie&quot; date -d &quot;1916/09/30 16:00 UTC&quot;<br>
Sun Oct  1 03:00:00 EST 1916<br>
% TZ=&quot;$PWD/build/zoneinfo/<u></u>Antarctica/Macquarie&quot; date -d &quot;1916/09/30 15:59 UTC&quot;<br>
Sun Oct  1 01:59:00 EST 1916<br>
<br>
Using this commit, if I change the date of the first line of the Zone from &quot;1899<br>
Nov&quot; back to &quot;1911&quot;, it starts to work again. <br>
Here is the change set that causes the confusion.<br>
<br>
<a href="https://github.com/eggert/tz/commit/188b29d9664cfcf0384e515c69f94a2dfc27c673" target="_blank">https://github.com/eggert/tz/<u></u>commit/<u></u>188b29d9664cfcf0384e515c69f94a<u></u>2dfc27c673</a><br>
<br>
I am on a 32-bit system but in my experience, I&#39;m always able to get a correct<br>
timezone offset for dates in 1916 regardless of whether or not the zone begins<br>
before the range of a 32-bit POSIX time.<br>
<br>
--<br>
Alan Gutierrez ~ @bigeasy<br>
</blockquote></div><br></div>