From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp12.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id sAV2Bn3ZxmOiHQEAbAwnHQ (envelope-from ) for ; Tue, 17 Jan 2023 18:23:09 +0100 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp12.migadu.com with LMTPS id oKlpBn3ZxmPggAEAauVa8A (envelope-from ) for ; Tue, 17 Jan 2023 18:23:09 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 94D782B0D7 for ; Tue, 17 Jan 2023 18:23:08 +0100 (CET) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pHpfH-00087p-9V; Tue, 17 Jan 2023 12:22:27 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pHpfG-000869-7L for emacs-orgmode@gnu.org; Tue, 17 Jan 2023 12:22:26 -0500 Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pHpfE-0006cB-9K for emacs-orgmode@gnu.org; Tue, 17 Jan 2023 12:22:25 -0500 Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1pHpfA-0002om-WE for emacs-orgmode@gnu.org; Tue, 17 Jan 2023 18:22:21 +0100 X-Injected-Via-Gmane: http://gmane.org/ To: emacs-orgmode@gnu.org From: Max Nikulin Subject: Observation of hysteresis in a GNU libc time conversion function Date: Wed, 18 Jan 2023 00:22:12 +0700 Message-ID: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------VLd7U7CyehkLw6LV0SMVBScE" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 Content-Language: en-US Received-SPF: pass client-ip=116.202.254.214; envelope-from=geo-emacs-orgmode@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: 28 X-Spam_score: 2.8 X-Spam_bar: ++ X-Spam_report: (2.8 / 5.0 requ) BAYES_00=-1.9, DC_PNG_UNO_LARGO=0.001, DKIM_ADSP_CUSTOM_MED=0.001, FORGED_GMAIL_RCVD=1, FORGED_MUA_MOZILLA=2.309, FREEMAIL_FORGED_FROMDOMAIN=0.249, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.25, NML_ADSP_CUSTOM_MED=0.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed), No valid DKIM" header.from=gmail.com (policy=none) ARC-Seal: i=1; s=key1; d=yhetil.org; t=1673976188; a=rsa-sha256; cv=none; b=kUAFiNB+e8qBjpo6XRSRWaZ4r9JqsTLae1vvR6uVDiU+R2T1Hg0kfzSFHJptNh6s3XJcHE bVoB/vQ1Xna7DRM2FeOr//ylGy5nswMPo/wc1OUS/Q7iyX2MlhhAuQsPx/3nVl6BApms8Z S5Pc7mzDrSjTvy8gDMuNKEnp/84FXaYgt+h8UWnIJDFAvFoBVFnSOlnuegOGU4D8s2iifa 9YEeYUvt8shm84dyVmh353zUGM8zU7tp9a3l4HINm2AKFQZvHmNM2MXziZ6FZGX9SVQEAI vQKlIz3sjgkUt/9gqIN/muJd14bQ4xM2LOs+2V67qYzfNYD7CvZrdxH8dlpygA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1673976188; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type:list-id:list-help:list-unsubscribe: list-subscribe:list-post; bh=0wfauR9OZED/O270gVh3d509abLwJf/6tMH0Q78Niew=; b=FrleYqiq0yy2MYOL59TG3AirjUXUHoLE7tWgVc6On0TCWuHP05oZy+vfm27vq3Mra9bIfq FldYID7/T/kxlYS5ASSbPNDc75DTcAxROA1/EobqJPd0tlfRH5FC3OjMwM2qmJtFld7Dx2 m5QeAbubtC9mBD5zY3viznjGHJdBLUiI2T+Eq5TkBgrnGbCHQ/D2/Rr3gdg2nnuMVt2fyS ifsLlgzGIaaHzv3xcP4I2e8MYQC/rtNg6tUTaZ2ihxUziLcNkAIURB607IO0V1GpjZMFDb KmHjjSGlIBw4KEC4Lfgey3jvbySZMQO2OM1iVUUkCWE5ytCeAK0D0kzJPW3CZA== Authentication-Results: aspmx1.migadu.com; dkim=none; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org"; dmarc=fail reason="SPF not aligned (relaxed), No valid DKIM" header.from=gmail.com (policy=none) X-Migadu-Spam-Score: -2.33 X-Spam-Score: -2.33 X-Migadu-Queue-Id: 94D782B0D7 X-Migadu-Scanner: scn1.migadu.com X-TUID: PP61arFH+9LP This is a multi-part message in MIME format. --------------VLd7U7CyehkLw6LV0SMVBScE Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit #+title: Observation of hysteresis in a GNU libc time conversion function #+begin_abstract The ~mktime~ function in GNU libc for specific arguments may possess properties similar to ferromagnetic materials. Dependence of returned value on arguments passed during earler calls gives evidences that it has hidden state. #+end_abstract I was experimenting with a code sample posted to the thread on support of time zones in Org. I noticed rather strange behavior of ~encode-time~ and thus underlying ~mktime~ function. At first I considered it as non-deterministic, but later I realized that time zone offset calculated earlier may affect following calls. I was aware that the function is not pure since it calls ~tzset~ to initialize time zone from the ~TZ~ environment variable and e.g. ~tzname~ global variable. It was a surprise that the function can not be considered even as a stable one. Passing same arguments may lead to different results. I am unsure whether it is intentional or at least known property. #+begin_src elisp :exports nil :results silent (require 'ob-shell) (require 'ob-gnuplot) #+end_src Let's take some backward time transition, so with ambiguous local time, where daylight saving time state is not changed and preferably is not in action. As a result it is impossible to disambiguate whether local time is before or after time jump. Attempt to specify ~dst~ as ~t~ (or set ~t.tm_isdst = 1~ for ~mktime~) will lead to an error. #+begin_src sh :results verbatim :exports both zdump -v Africa/Juba | grep 2021 #+end_src #+RESULTS: : Africa/Juba Sun Jan 31 20:59:59 2021 UT = Sun Jan 31 23:59:59 2021 EAT isdst=0 gmtoff=10800 : Africa/Juba Sun Jan 31 21:00:00 2021 UT = Sun Jan 31 23:00:00 2021 CAT isdst=0 gmtoff=7200 We may convert broken down local time representation around 23:30 local time for a sequence of time moments passing values to ~encode-time~ in increasing and decreasing their order. Under the hood the function calls the =mktime(3)= function. #+name: timestamp #+header: :exports code #+begin_src elisp :var tz="Africa/Juba" :var t0='(0 30 23 31 1 2021) (let* ((f (lambda (minutes) (float-time (encode-time (list (nth 0 t0) (+ (nth 1 t0) minutes) (nth 2 t0) (nth 3 t0) (nth 4 t0) (nth 5 t0) nil -1 tz))))) (dt '(-90 -60 -31 -30 -29 -15 0 15 29 30 31 60 90)) (values (mapcar (lambda (m) (cons m (funcall f m))) dt)) (ts0 (cdr (nth (/ (length values) 2) values)))) (mapcar (lambda (pair) (let ((m (car pair))) (list m (- (cdr pair) ts0) (- (funcall f m) ts0)))) (reverse values))) #+end_src #+RESULTS: timestamp | 90 | 9000.0 | 9000.0 | | 60 | 7200.0 | 7200.0 | | 31 | 5460.0 | 5460.0 | | 30 | 5400.0 | 5400.0 | | 29 | 1740.0 | 5340.0 | | 15 | 900.0 | 4500.0 | | 0 | 0.0 | 3600.0 | | -15 | -900.0 | 2700.0 | | -29 | -1740.0 | 1860.0 | | -30 | -1800.0 | 1800.0 | | -31 | -1860.0 | -1860.0 | | -60 | -3600.0 | -3600.0 | | -90 | -5400.0 | -5400.0 | #+begin_src gnuplot :file mktime-hyst.png :var data=timestamp set key bottom right set xlabel 'minutes' set ylabel 'UNIX epoch difference, seconds' set title 'Hysteresis in GNU libc mktime' plot data using 1:2 with lp title 'increasing', \ '' using 1:3 with lp title 'decreasing' #+end_src #+RESULTS: [[file:mktime-hyst.png]] So result for the same arguments may depend on previous calls. Likely it is due to a [[https://sourceware.org/git/?p=glibc.git;a=blob;f=time/mktime.c;h=94a4320e6ca9d935fc534991f9b57a2f1cc185de;hb=HEAD#l544][static variable]] used in the =mktime.c= file. Such a variable appeared in the commit [[https://sourceware.org/git/?p=glibc.git;a=commit;h=80fd73873b][80fd73873b]] #+begin_example Fri Sep 29 03:43:51 1995 Paul Eggert Rewrite mktime from scratch for performance, and for correctness in the presence of leap seconds. #+end_example Perhaps hidden internal state may be used to disambiguate local time values around backward time steps with unchanged daylight saving time. Unfortunately relying on such implementation details hardly can be considered as a robust approach. --------------VLd7U7CyehkLw6LV0SMVBScE Content-Type: image/png; name="mktime-hyst.png" Content-Disposition: attachment; filename="mktime-hyst.png" Content-Transfer-Encoding: base64 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 yX8oQq5TKo3bkAAAAABJRU5ErkJggg== --------------VLd7U7CyehkLw6LV0SMVBScE--