emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Observation of hysteresis in a GNU libc time conversion function
@ 2023-01-17 17:22 Max Nikulin
  2023-01-18  9:54 ` Ihor Radchenko
  0 siblings, 1 reply; 5+ messages in thread
From: Max Nikulin @ 2023-01-17 17:22 UTC (permalink / raw)
  To: emacs-orgmode

[-- Attachment #1: Type: text/plain, Size: 4131 bytes --]

#+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.

[-- Attachment #2: mktime-hyst.png --]
[-- Type: image/png, Size: 7420 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-01-19 10:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-17 17:22 Observation of hysteresis in a GNU libc time conversion function Max Nikulin
2023-01-18  9:54 ` Ihor Radchenko
2023-01-18 16:32   ` Max Nikulin
2023-01-18 16:38     ` Max Nikulin
2023-01-19 10:31     ` Ihor Radchenko

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

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