public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: DJ Delorie <dj@redhat.com>
To: "Carlos O'Donell" <carlos@redhat.com>
Cc: eggert@cs.ucla.edu, libc-alpha@sourceware.org
Subject: Re: [swbz 29035] mktime vs non-DST
Date: Thu, 18 Aug 2022 17:17:19 -0400	[thread overview]
Message-ID: <xnpmgx5k0w.fsf@greed.delorie.com> (raw)
In-Reply-To: <8c91bbc3-95cc-88d0-ffe9-5da08fcfdf38@redhat.com>

"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.


  parent reply	other threads:[~2022-08-18 21:17 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-17 21:18 DJ Delorie
2022-08-17 21:50 ` Carlos O'Donell
2022-08-17 23:10 ` Paul Eggert
2022-08-18  1:39   ` DJ Delorie
2022-08-18  2:37     ` Carlos O'Donell
2022-08-18  3:16       ` Paul Eggert
2022-08-18  4:05         ` Carlos O'Donell
2022-08-18 21:17       ` DJ Delorie [this message]
2022-08-18 21:57         ` Paul Eggert
2022-08-18 22:40           ` DJ Delorie
2022-08-18 22:58             ` Paul Eggert
2022-08-19 18:15               ` DJ Delorie
2022-08-19 22:04                 ` Paul Eggert
2022-08-18  3:02     ` Paul Eggert
2022-09-08 20:25   ` DJ Delorie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=xnpmgx5k0w.fsf@greed.delorie.com \
    --to=dj@redhat.com \
    --cc=carlos@redhat.com \
    --cc=eggert@cs.ucla.edu \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).