[swbz 29035] mktime vs non-DST

DJ Delorie dj@redhat.com
Thu Aug 18 21:17:19 GMT 2022


"Carlos O'Donell" <carlos@redhat.com> writes:
> May you please share some examples you have from your analysis and share how
> they are different before and now? How far back does the old behaviour go?

Here are some snippets from the test program I wrote to deduce what
mktime was doing.  The program uses "zdump -v" to get all the
transitions in a zone, and converts that in to a table of time_t's and
struct tm's for each transition boundary.  The table is limited to
1979..2021.

Once the table is built, every transition edge, before and after, is
run through mktime() to verify it returns the given time_t with the
given tm_isdst.  I convert the time_t back to gmtime and localtime,
but do not yet verify the results.  Next, for transitions that involve
a step forward in time (i.e. where there's never an ambiguous wall
clock time), I test mktime with tm_isdst = {-1, 0, 1} and see what
each returns.  This is deemed "broken" if it results in a time_t
different than indicated.

The two timezones I'm using here are America/NewYork (typical
winter/summer STD/DST transitions) and Asia/Tokyo (which hasn't had
DST since 1952) as extremes.

FYI glibc 2.12 reports the same results as 2.28

glibc 2.28 (RHEL 8) (partial listing):

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
"America/New_York", 1615705199, = Sun, 2021-Mar-14  6:59:59 = Sun, 2021-Mar-14  1:59:59 = 0 -18000
1615705199 -> Sun Mar 14 06:59:59 2021 gmt, or Sun Mar 14 01:59:59 2021 local
  - UNK:1615705199 returned  Sun, 2021-Mar-14  1:59:59 STD
  - STD:1615705199 returned  Sun, 2021-Mar-14  1:59:59 STD
broken isdst=1: 1615701599 instead of 1615705199 (-3600)
  - DST:1615701599 returned  Sun, 2021-Mar-14  0:59:59 STD

"America/New_York", 1615705200, = Sun, 2021-Mar-14  7:00:00 = Sun, 2021-Mar-14  3:00:00 = 1 -14400
1615705200 -> Sun Mar 14 07:00:00 2021 gmt, or Sun Mar 14 03:00:00 2021 local
  - UNK:1615705200 returned  Sun, 2021-Mar-14  3:00:00 DST
broken isdst=0: 1615708800 instead of 1615705200 (+3600)
  - STD:1615708800 returned  Sun, 2021-Mar-14  4:00:00 DST
  - DST:1615705200 returned  Sun, 2021-Mar-14  3:00:00 DST

"America/New_York", 1636264799, = Sun, 2021-Nov-07  5:59:59 = Sun, 2021-Nov-07  1:59:59 = 1 -14400
1636264799 -> Sun Nov  7 05:59:59 2021 gmt, or Sun Nov  7 01:59:59 2021 local

"America/New_York", 1636264800, = Sun, 2021-Nov-07  6:00:00 = Sun, 2021-Nov-07  1:00:00 = 0 -18000
1636264800 -> Sun Nov  7 06:00:00 2021 gmt, or Sun Nov  7 01:00:00 2021 local

"America/New_York", 1641038400, = Sat, 2022-Jan-01 12:00:00 = Sat, 2022-Jan-01  7:00:00 = -1 -18000
1641038400 -> Sat Jan  1 12:00:00 2022 gmt, or Sat Jan  1 07:00:00 2022 local
  - UNK:1641038400 returned  Sat, 2022-Jan-01  7:00:00 STD
  - STD:1641038400 returned  Sat, 2022-Jan-01  7:00:00 STD
broken isdst=1: 1641034800 instead of 1641038400 (-3600)
  - DST:1641034800 returned  Sat, 2022-Jan-01  6:00:00 STD

"America/New_York", 1656676800, = Fri, 2022-Jul-01 12:00:00 = Fri, 2022-Jul-01  8:00:00 = -1 -14400
1656676800 -> Fri Jul  1 12:00:00 2022 gmt, or Fri Jul  1 08:00:00 2022 local
  - UNK:1656676800 returned  Fri, 2022-Jul-01  8:00:00 DST
broken isdst=0: 1656680400 instead of 1656676800 (+3600)
  - STD:1656680400 returned  Fri, 2022-Jul-01  9:00:00 DST
  - DST:1656676800 returned  Fri, 2022-Jul-01  8:00:00 DST

"Asia/Tokyo", 1641038400, = Sat, 2022-Jan-01 12:00:00 = Sat, 2022-Jan-01 21:00:00 = -1 32400
1641038400 -> Sat Jan  1 12:00:00 2022 gmt, or Sat Jan  1 21:00:00 2022 local
  - UNK:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - STD:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - DST:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD

"Asia/Tokyo", 1656676800, = Fri, 2022-Jul-01 12:00:00 = Fri, 2022-Jul-01 21:00:00 = -1 32400
1656676800 -> Fri Jul  1 12:00:00 2022 gmt, or Fri Jul  1 21:00:00 2022 local
  - UNK:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - STD:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - DST:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Note that mktime is "broken" at a transition if the tm_isdst passed
doesn't match the tm_isdst that localtime would have returned, in
that, the time is off by an hour.  Whether this is desirable behavior
or not is up to you ;-)

The last four tests (showing tm_isdst passed, returned time_t, and
localtime for that time_t) are testing mktime in January and July, far
from transitions, in every zone (Tokyo has no transitions, so these
tests are all you see from it).  NewYork has the same symptoms as at
transitions - a mismatched tm_isdst results in a wall clock time
that's off by an hour.  For the Asia/Tokyo case, mktime ignores
tm_isdst (apparently) and always returns standard time.

The tests for America/NewYork are identical across all the glibc patch
variants, so I'll skip those from now on.

As of glibc 2.29, the Asia/Tokyo results look like this:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
"Asia/Tokyo", 1641038400, = Sat, 2022-Jan-01 12:00:00 = Sat, 2022-Jan-01 21:00:00 = -1 32400
1641038400 -> Sat Jan  1 12:00:00 2022 gmt, or Sat Jan  1 21:00:00 2022 local
  - UNK:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - STD:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
broken isdst=1: -1 instead of 1641038400 (-1641038401)
  - DST:-1 returned  Thu, 1970-Jan-01  8:59:59 STD

"Asia/Tokyo", 1656676800, = Fri, 2022-Jul-01 12:00:00 = Fri, 2022-Jul-01 21:00:00 = -1 32400
1656676800 -> Fri Jul  1 12:00:00 2022 gmt, or Fri Jul  1 21:00:00 2022 local
  - UNK:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - STD:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
broken isdst=1: -1 instead of 1656676800 (-1656676801)
  - DST:-1 returned  Thu, 1970-Jan-01  8:59:59 STD
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Note that a mismatched tm_isdst now returns -1/EOVERFLOW.

If you take out the two lines I noted in my initial email, you get this instead:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
"Asia/Tokyo", 1641038400, = Sat, 2022-Jan-01 12:00:00 = Sat, 2022-Jan-01 21:00:00 = -1 32400
1641038400 -> Sat Jan  1 12:00:00 2022 gmt, or Sat Jan  1 21:00:00 2022 local
  - UNK:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - STD:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - DST:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD

"Asia/Tokyo", 1656676800, = Fri, 2022-Jul-01 12:00:00 = Fri, 2022-Jul-01 21:00:00 = -1 32400
1656676800 -> Fri Jul  1 12:00:00 2022 gmt, or Fri Jul  1 21:00:00 2022 local
  - UNK:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - STD:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - DST:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Note that this matches the 2.28 behavior, but not the America/NewYork
behavior.

If you add Paul's patches to sync to gnulib, you get this:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
"Asia/Tokyo", 1641038400, = Sat, 2022-Jan-01 12:00:00 = Sat, 2022-Jan-01 21:00:00 = -1 32400
1641038400 -> Sat Jan  1 12:00:00 2022 gmt, or Sat Jan  1 21:00:00 2022 local
  - UNK:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
  - STD:1641038400 returned  Sat, 2022-Jan-01 21:00:00 STD
broken isdst=1: 1641034800 instead of 1641038400 (-3600)
  - DST:1641034800 returned  Sat, 2022-Jan-01 20:00:00 STD

"Asia/Tokyo", 1656676800, = Fri, 2022-Jul-01 12:00:00 = Fri, 2022-Jul-01 21:00:00 = -1 32400
1656676800 -> Fri Jul  1 12:00:00 2022 gmt, or Fri Jul  1 21:00:00 2022 local
  - UNK:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
  - STD:1656676800 returned  Fri, 2022-Jul-01 21:00:00 STD
broken isdst=1: 1656673200 instead of 1656676800 (-3600)
  - DST:1656673200 returned  Fri, 2022-Jul-01 20:00:00 STD
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

As I noted before, this is consistent with America/NewYork, but still
differs from 2.28.



More information about the Libc-alpha mailing list