From: Paul Eggert <eggert@cs.ucla.edu>
To: Max Nikulin <manikulin@gmail.com>
Cc: emacs-orgmode@gnu.org, 54764@debbugs.gnu.org
Subject: Re: bug#54764: encode-time: make DST and TIMEZONE fields of the list argument optional ones
Date: Mon, 18 Apr 2022 19:02:03 -0700 [thread overview]
Message-ID: <f9d9d26c-1974-b52a-8f4d-49167676c102@cs.ucla.edu> (raw)
In-Reply-To: <5cd820d4-ae67-43d4-9e63-c284d51ff1e4@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2957 bytes --]
Here are the main points I see about making timestamps work better in
Org mode, and related patches to how Emacs handles timestamps.
* Max would like encode-time to treat a list (SS MM HH DD MM YYYY) as if
it were (SS MM HH DD MM YYYY nil -1 nil), as that would be more
convenient for how Org mode deals with ambiguous local timestamps. This
is relatively easy to add for Emacs 29+, and is done in first of the
attached proposed patches to Emacs master.
* As I understand it, Max would like a function that emulate Emacs 29
encode-time with one argument, even if running in Emacs versions back to
Emacs 25. I suppose such a function would also need to implement Emacs
27+ encode-time's support for subsecond resolution. E.g.,
(org-encode-time '((44604411568 . 1000000000) 55 0 19 4 2022 - -1 t))
should return (1650329744604411568 . 1000000000) even in Emacs 25 and 26.
* There are three other Emacs timestamp changes I should mention that
might be relevant to Org mode:
** 1. Although in Emacs 28 functions like (time-convert nil t) return a
timestamp resolution of 1 ns, in Emacs 29 I plan to fix them so that
they return the system clock resolution, which is often coarser than 1
ns. This is done in the 4th attached patch.
** 2. In Emacs 29 format-time-string should support a new format "%-N"
which outputs only enough digits for the system clock resolution. (This
is the same as GNU "date".) This is done in the 5th attached patch.
** 3. Emacs 29 current-time and related functions should generate a
(TICKS . HZ) timestamp instead of the old (HIGH LOW MICROSECS PICOSECS)
timestamp. This change has been planned for some time; it was announced
in Emacs 27. As far as I know Org mode is already ready for this change
but I thought I'd mention it again here. This is done in the last
attached patch.
* My last topic in this email is Max's request for a feature that I'm
not planning to put into Emacs 29 as it'll require more thought. This
addresses the problem where your TZ is "Africa/Juba" and you want to
encode a timestamp like "2021-01-31 23:30" which is ambiguous since at
24:00 that day Juba moved standard time back by an hour. Unfortunately
the underlying C mktime function does not allow disambiguation in the
rare situation where standard time moves further west of Greenwich.
Addressing this problem would require rewriting mktime from scratch in
Elisp, or using heuristics that would occasionally fail, or (my
favorite) extending glibc mktime to treat tm_isdst values other than
-1,0,1 to support disambiguating such timestamps. In the meantime, one
can disambiguate such timestamps in Elisp by using numeric time zones, e.g.:
(format-time-string "%F %T %z"
(encode-time '(0 30 23 31 1 2021 - -1 TZ))
"Africa/Juba")
yields "2021-01-31 23:30:00 +0200" if TZ is 7200, and "2021-01-31
23:30:00 +0300" if TZ is 10800. And perhaps this is the right way to go
in the long run anyway.
[-- Attachment #2: 0001-Support-encode-time-list-s-m-h-D-M-Y.patch --]
[-- Type: text/x-patch, Size: 4727 bytes --]
From 3d02a8e1192a782a16ffdee4940612f69a12629f Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:26 -0700
Subject: [PATCH 1/6] Support (encode-time (list s m h D M Y))
* src/timefns.c (Fencode_time): Add support for a 6-elt list arg.
Requested by Max Nikulin for Org (bug#54764).
* test/src/timefns-tests.el (encode-time-alternate-apis): New test.
---
doc/lispref/os.texi | 5 +++++
etc/NEWS | 5 +++++
src/timefns.c | 21 +++++++++++++++------
test/src/timefns-tests.el | 9 +++++++++
4 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index cabae08970..bfcd51318e 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1660,6 +1660,11 @@ Time Conversion
handle situations like this you can use a numeric @var{zone} to
disambiguate instead.
+The first argument can also be a list @code{(@var{second} @var{minute}
+@var{hour} @var{day} @var{month} @var{year})}, which is treated like
+the list @code{(@var{second} @var{minute} @var{hour} @var{day}
+@var{month} @var{year} nil -1 nil)}.
+
As an obsolescent calling convention, this function can be given six
or more arguments. The first six arguments @var{second},
@var{minute}, @var{hour}, @var{day}, @var{month}, and @var{year}
diff --git a/etc/NEWS b/etc/NEWS
index 3e7788277d..c5a136ea68 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1950,6 +1950,11 @@ For example, '(time-add nil '(1 . 1000))' no longer warns that the
'(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a
temporary transition aid for Emacs 27, has served its purpose.
++++
+** 'encode-time' now also accepts a 6-element list with just time and date.
+(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR)) is now short for
+(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR nil -1 nil)).
+
+++
** 'date-to-time' now assumes earliest values if its argument lacks
month, day, or time. For example, (date-to-time "2021-12-04") now
diff --git a/src/timefns.c b/src/timefns.c
index 7a4a7075ed..b0b84a438c 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -1620,6 +1620,9 @@ DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0,
saving time, nil for standard time, and -1 to cause the daylight
saving flag to be guessed.
+TIME can also be a list (SECOND MINUTE HOUR DAY MONTH YEAR), which is
+equivalent to (SECOND MINUTE HOUR DAY MONTH YEAR nil -1 nil).
+
As an obsolescent calling convention, if this function is called with
6 or more arguments, the first 6 arguments are SECOND, MINUTE, HOUR,
DAY, MONTH, and YEAR, and specify the components of a decoded time.
@@ -1645,7 +1648,7 @@ DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0,
if (nargs == 1)
{
Lisp_Object tail = a;
- for (int i = 0; i < 9; i++, tail = XCDR (tail))
+ for (int i = 0; i < 6; i++, tail = XCDR (tail))
CHECK_CONS (tail);
secarg = XCAR (a); a = XCDR (a);
minarg = XCAR (a); a = XCDR (a);
@@ -1653,11 +1656,17 @@ DEFUN ("encode-time", Fencode_time, Sencode_time, 1, MANY, 0,
mdayarg = XCAR (a); a = XCDR (a);
monarg = XCAR (a); a = XCDR (a);
yeararg = XCAR (a); a = XCDR (a);
- a = XCDR (a);
- Lisp_Object dstflag = XCAR (a); a = XCDR (a);
- zone = XCAR (a);
- if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone))
- tm.tm_isdst = !NILP (dstflag);
+ if (! NILP (a))
+ {
+ CHECK_CONS (a);
+ a = XCDR (a);
+ CHECK_CONS (a);
+ Lisp_Object dstflag = XCAR (a); a = XCDR (a);
+ CHECK_CONS (a);
+ zone = XCAR (a);
+ if (SYMBOLP (dstflag) && !FIXNUMP (zone) && !CONSP (zone))
+ tm.tm_isdst = !NILP (dstflag);
+ }
}
else if (nargs < 6)
xsignal2 (Qwrong_number_of_arguments, Qencode_time, make_fixnum (nargs));
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index e7c464472d..08d06f27d9 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -225,6 +225,15 @@ encode-time-dst-numeric-zone
(encode-time '(29 31 17 30 4 2019 2 t 7200))
'(23752 27217))))
+(ert-deftest encode-time-alternate-apis ()
+ (let* ((time '(30 30 12 15 6 1970))
+ (time-1 (append time '(nil -1 nil)))
+ (etime (encode-time time)))
+ (should (time-equal-p etime (encode-time time-1)))
+ (should (time-equal-p etime (apply #'encode-time time)))
+ (should (time-equal-p etime (apply #'encode-time time-1)))
+ (should (time-equal-p etime (apply #'encode-time (append time '(nil)))))))
+
(ert-deftest float-time-precision ()
(should (= (float-time '(0 1 0 4025)) 1.000000004025))
(should (= (float-time '(1000000004025 . 1000000000000)) 1.000000004025))
--
2.35.1
[-- Attachment #3: 0002-Refactor-to-simplify-clock-resolution-support.patch --]
[-- Type: text/x-patch, Size: 4332 bytes --]
From 68bd5fdbb6a94fd90575e2e2199365a0c2b9db68 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:26 -0700
Subject: [PATCH 2/6] Refactor to simplify clock resolution support
* src/timefns.c (timespec_mpz, timespec_ticks):
New args HZ, RES. All callers changed.
(timespec_clockres_to_lisp): New function,
extended from timespec_to_lisp.
(timespec_to_lisp): Use it.
(make_lisp_time_clockres): New function, extended from make_lisp_time.
(make_lisp_time): Use it.
---
src/timefns.c | 61 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 43 insertions(+), 18 deletions(-)
diff --git a/src/timefns.c b/src/timefns.c
index b0b84a438c..3f8efadf54 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -482,30 +482,37 @@ mpz_set_time (mpz_t rop, time_t t)
mpz_set_uintmax (rop, t);
}
-/* Store into mpz[0] a clock tick count for T, assuming a
- TIMESPEC_HZ-frequency clock. Use mpz[1] as a temp. */
+/* Store into mpz[0] a clock tick count for T, assuming a HZ-frequency
+ clock with resolution RES ns (so that HZ*RES = TIMESPEC_HZ).
+ Use mpz[1] as a temp. */
static void
-timespec_mpz (struct timespec t)
+timespec_mpz (struct timespec t, long int hz, long int res)
{
- /* mpz[0] = sec * TIMESPEC_HZ + nsec. */
- mpz_set_ui (mpz[0], t.tv_nsec);
+ /* mpz[0] = sec * hz + nsec / res. */
+ mpz_set_ui (mpz[0], t.tv_nsec / res);
mpz_set_time (mpz[1], t.tv_sec);
- mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ);
+ mpz_addmul_ui (mpz[0], mpz[1], hz);
}
-/* Convert T to a Lisp integer counting TIMESPEC_HZ ticks. */
+/* Convert T to a Lisp integer counting HZ ticks each consisting
+ of RES ns. */
static Lisp_Object
-timespec_ticks (struct timespec t)
+timespec_ticks (struct timespec t, long int hz, long int res)
{
+ eassume (0 <= t.tv_nsec && t.tv_nsec < TIMESPEC_HZ);
+ eassume (0 < hz && hz <= TIMESPEC_HZ);
+ eassume (0 < res && res <= TIMESPEC_HZ);
+ eassume (hz * res == TIMESPEC_HZ);
+
/* For speed, use intmax_t arithmetic if it will do. */
intmax_t accum;
if (FASTER_TIMEFNS
- && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum)
- && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum))
+ && !INT_MULTIPLY_WRAPV (t.tv_sec, hz, &accum)
+ && !INT_ADD_WRAPV (t.tv_nsec / res, accum, &accum))
return make_int (accum);
/* Fall back on bignum arithmetic. */
- timespec_mpz (t);
+ timespec_mpz (t, hz, res);
return make_integer_mpz ();
}
@@ -565,9 +572,26 @@ lisp_time_seconds (struct lisp_time t)
return make_integer_mpz ();
}
-/* Convert T to a Lisp timestamp. */
+/* Return (TICKS . LISPHZ) for time T, assuming a LISPHZ,HZ,RES clock. */
+static Lisp_Object
+timespec_clockres_to_lisp (struct timespec t, Lisp_Object lisphz,
+ long int hz, long int res)
+{
+ return Fcons (timespec_ticks (t, hz, res), lisphz);
+}
+
+/* Return (TICKS . HZ) for time T, assuming a clock resolution of 1 ns. */
Lisp_Object
-make_lisp_time (struct timespec t)
+timespec_to_lisp (struct timespec t)
+{
+ return timespec_clockres_to_lisp (t, timespec_hz, TIMESPEC_HZ, 1);
+}
+
+/* Convert T to a Lisp timestamp, assuming a LISPHZ or HZ-frequency
+ clock with resolution RES ns (so that HZ*RES = TIMESPEC_HZ). */
+static Lisp_Object
+make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz,
+ long int hz, long int res)
{
if (CURRENT_TIME_LIST)
{
@@ -577,14 +601,14 @@ make_lisp_time (struct timespec t)
make_fixnum (ns / 1000), make_fixnum (ns % 1000 * 1000));
}
else
- return timespec_to_lisp (t);
+ return timespec_clockres_to_lisp (t, lisphz, hz, res);
}
-/* Return (TICKS . HZ) for time T. */
+/* Convert T to a Lisp timestamp. */
Lisp_Object
-timespec_to_lisp (struct timespec t)
+make_lisp_time (struct timespec t)
{
- return Fcons (timespec_ticks (t), timespec_hz);
+ return make_lisp_time_clockres (t, timespec_hz, TIMESPEC_HZ, 1);
}
/* Return NUMERATOR / DENOMINATOR, rounded to the nearest double.
@@ -747,7 +771,8 @@ decode_time_components (enum timeform form,
}
case TIMEFORM_NIL:
- return decode_ticks_hz (timespec_ticks (current_timespec ()),
+ return decode_ticks_hz (timespec_ticks (current_timespec (),
+ TIMESPEC_HZ, 1),
timespec_hz, result, dresult);
default:
--
2.35.1
[-- Attachment #4: 0003-Add-Gnulib-gettime-res-module.patch --]
[-- Type: text/x-patch, Size: 5226 bytes --]
From 8c25372709d256d83858be454987137dc202b725 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:27 -0700
Subject: [PATCH 3/6] Add Gnulib gettime-res module
* admin/merge-gnulib (GNULIB_MODULES): Add gettime-res.
* lib/gettime-res.c: New file, copied from Gnulib.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
---
admin/merge-gnulib | 3 +-
lib/gettime-res.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++
lib/gnulib.mk.in | 9 ++++++
m4/gnulib-comp.m4 | 3 ++
4 files changed, 92 insertions(+), 1 deletion(-)
create mode 100644 lib/gettime-res.c
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index ea3d23686f..0279d1f99d 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -37,7 +37,8 @@ GNULIB_MODULES=
fchmodat fcntl fcntl-h fdopendir file-has-acl
filemode filename filevercmp flexmember fpieee
free-posix fstatat fsusage fsync futimens
- getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
+ getloadavg getopt-gnu getrandom
+ gettime gettime-res gettimeofday gitlog-to-changelog
ieee754-h ignore-value intprops largefile libgmp lstat
manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime
nanosleep nproc nstrftime
diff --git a/lib/gettime-res.c b/lib/gettime-res.c
new file mode 100644
index 0000000000..611f83ad27
--- /dev/null
+++ b/lib/gettime-res.c
@@ -0,0 +1,78 @@
+/* Get the system clock resolution.
+
+ Copyright 2021-2022 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#include <config.h>
+
+#include "timespec.h"
+
+static long int _GL_ATTRIBUTE_CONST
+gcd (long int a, long int b)
+{
+ while (b != 0)
+ {
+ long int r = a % b;
+ a = b;
+ b = r;
+ }
+ return a;
+}
+
+/* Return the system time resolution in nanoseconds. */
+
+long int
+gettime_res (void)
+{
+ struct timespec res;
+#if defined CLOCK_REALTIME && HAVE_CLOCK_GETRES
+ clock_getres (CLOCK_REALTIME, &res);
+#elif defined HAVE_TIMESPEC_GETRES
+ timespec_getres (&res, TIME_UTC);
+#else
+ /* Guess high and let the later code deduce better. */
+ res.tv_sec = 1;
+ res.tv_nsec = 0;
+#endif
+
+ /* On all Gnulib platforms the following calculations do not overflow. */
+
+ long int hz = TIMESPEC_HZ;
+ long int r = hz * res.tv_sec + res.tv_nsec;
+
+ /* On some platforms, clock_getres (CLOCK_REALTIME, ...) yields a
+ too-large resolution, under the mistaken theory that it should
+ return the timer interval. For example, on AIX 7.2 POWER8
+ clock_getres yields 10 ms even though clock_gettime yields 1 µs
+ resolution. Work around the problem with high probability by
+ trying clock_gettime several times and observing the resulting
+ bounds on resolution. */
+ for (int i = 0; 1 < r && i < 32; i++)
+ {
+ struct timespec now = current_timespec ();
+ r = gcd (r, now.tv_nsec ? now.tv_nsec : hz);
+ }
+
+ return r;
+}
+
+/*
+ * Hey Emacs!
+ * Local Variables:
+ * coding: utf-8
+ * End:
+ */
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index bbb05fdba5..fbc199faaf 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -114,6 +114,7 @@
# getopt-gnu \
# getrandom \
# gettime \
+# gettime-res \
# gettimeofday \
# gitlog-to-changelog \
# ieee754-h \
@@ -2188,6 +2189,14 @@ libgnu_a_SOURCES += gettime.c
endif
## end gnulib module gettime
+## begin gnulib module gettime-res
+ifeq (,$(OMIT_GNULIB_MODULE_gettime-res))
+
+libgnu_a_SOURCES += gettime-res.c
+
+endif
+## end gnulib module gettime-res
+
## begin gnulib module gettimeofday
ifeq (,$(OMIT_GNULIB_MODULE_gettimeofday))
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index fb5f1b52a4..a04ec44be9 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -112,6 +112,7 @@ AC_DEFUN
# Code from module getrandom:
# Code from module gettext-h:
# Code from module gettime:
+ # Code from module gettime-res:
# Code from module gettimeofday:
# Code from module gitlog-to-changelog:
# Code from module group-member:
@@ -371,6 +372,7 @@ AC_DEFUN
[test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1])
gl_SYS_RANDOM_MODULE_INDICATOR([getrandom])
gl_GETTIME
+ gl_GETTIME_RES
gl_FUNC_GETTIMEOFDAY
gl_CONDITIONAL([GL_COND_OBJ_GETTIMEOFDAY],
[test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1])
@@ -1270,6 +1272,7 @@ AC_DEFUN
lib/getopt_int.h
lib/getrandom.c
lib/gettext.h
+ lib/gettime-res.c
lib/gettime.c
lib/gettimeofday.c
lib/gl_openssl.h
--
2.35.1
[-- Attachment #5: 0004-Use-CLOCK_REALTIME-resolution-for-TICKS-.-HZ.patch --]
[-- Type: text/x-patch, Size: 8623 bytes --]
From 9c42f5f9ebc5b4e5d7bd0c33a0ce7de27c27d893 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:27 -0700
Subject: [PATCH 4/6] Use CLOCK_REALTIME resolution for (TICKS . HZ)
This gives Elisp code a clearer view of timestamps, for uses like
(time-convert nil t).
* src/emacs.c (main): Call init_timefns earlier.
* src/keyboard.c (Fcurrent_idle_time):
* src/sysdep.c (Fcurrent_time):
Use make_lisp_realtime instead of make_lisp_time,
for realtime timestamps (e.g., they come from gettime).
* src/sysdep.c (make_lisp_s_us): Also define if HAVE_GETRUSAGE.
Simplify by calling make_lisp_time_clockres.
(Fget_internal_run_time): Fix resolution by calling make_lisp_s_us.
* src/timefns.c (realtime_lisphz, realtime_hz, realtime_res):
New static vars.
(init_time_res): New function.
(init_timefns): Initialize the new vars
(make_lisp_time_clockres): Now extern.
(make_lisp_realtime): New function.
---
etc/NEWS | 6 ++++++
src/emacs.c | 7 ++++---
src/fileio.c | 5 ++++-
src/keyboard.c | 4 ++--
src/sysdep.c | 14 ++++++--------
src/systime.h | 3 +++
src/timefns.c | 36 +++++++++++++++++++++++++++++++++---
7 files changed, 58 insertions(+), 17 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index c5a136ea68..38317fef03 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1950,6 +1950,12 @@ For example, '(time-add nil '(1 . 1000))' no longer warns that the
'(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a
temporary transition aid for Emacs 27, has served its purpose.
++++
+** (TICKS . HZ) timestamps now report system clock resolution.
+For example, the macOS system clock resolution is 1 μs so
+(time-convert nil t) now acts like (time-convert nil 1000000).
+Formerly, time-convert used a clock resolution of 1 ns regardless.
+
+++
** 'encode-time' now also accepts a 6-element list with just time and date.
(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR)) is now short for
diff --git a/src/emacs.c b/src/emacs.c
index 3100852b2c..15a4a25770 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1894,6 +1894,10 @@ main (int argc, char **argv)
init_signals ();
+ /* This calls putenv and so must precede init_process_emacs.
+ It must also precede init_window_once, which creates timestamps. */
+ init_timefns ();
+
noninteractive1 = noninteractive;
/* Perform basic initializations (not merely interning symbols). */
@@ -2383,9 +2387,6 @@ main (int argc, char **argv)
init_charset ();
- /* This calls putenv and so must precede init_process_emacs. */
- init_timefns ();
-
init_editfns ();
/* These two call putenv. */
diff --git a/src/fileio.c b/src/fileio.c
index c418036fc6..2a857d10dd 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -5840,7 +5840,10 @@ DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
mtime = make_timespec (0, UNKNOWN_MODTIME_NSECS - flag);
}
else
- mtime = lisp_time_argument (time_flag);
+ {
+ mtime = lisp_time_argument (time_flag);
+ /* FIXME: Do not assume mtime resolution is 1 ns. */
+ }
current_buffer->modtime = mtime;
current_buffer->modtime_size = -1;
diff --git a/src/keyboard.c b/src/keyboard.c
index 19c8fdf1dc..3eb0694eda 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4668,8 +4668,8 @@ DEFUN ("current-idle-time", Fcurrent_idle_time, Scurrent_idle_time, 0, 0, 0,
(void)
{
if (timespec_valid_p (timer_idleness_start_time))
- return make_lisp_time (timespec_sub (current_timespec (),
- timer_idleness_start_time));
+ return make_lisp_realtime (timespec_sub (current_timespec (),
+ timer_idleness_start_time));
return Qnil;
}
diff --git a/src/sysdep.c b/src/sysdep.c
index 36636d0ed5..b15d5c359e 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -3169,16 +3169,14 @@ list_system_processes (void)
#endif /* !defined (WINDOWSNT) */
-#if defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__
+#if (defined HAVE_GETRUSAGE \
+ || defined __FreeBSD__ || defined DARWIN_OS || defined __OpenBSD__)
static Lisp_Object
make_lisp_s_us (time_t s, long us)
{
- Lisp_Object sec = make_int (s);
- Lisp_Object usec = make_fixnum (us);
- Lisp_Object hz = make_fixnum (1000000);
- Lisp_Object ticks = CALLN (Fplus, CALLN (Ftimes, sec, hz), usec);
- return Ftime_convert (Fcons (ticks, hz), Qnil);
+ return make_lisp_time_clockres (make_timespec (s, us * 1000),
+ make_fixnum (1000000), 1000000, 1000);
}
#endif
@@ -4238,7 +4236,7 @@ DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
#ifdef HAVE_GETRUSAGE
struct rusage usage;
time_t secs;
- int usecs;
+ long int usecs;
if (getrusage (RUSAGE_SELF, &usage) < 0)
/* This shouldn't happen. What action is appropriate? */
@@ -4252,7 +4250,7 @@ DEFUN ("get-internal-run-time", Fget_internal_run_time, Sget_internal_run_time,
usecs -= 1000000;
secs++;
}
- return make_lisp_time (make_timespec (secs, usecs * 1000));
+ return make_lisp_s_us (secs, usecs);
#else /* ! HAVE_GETRUSAGE */
#ifdef WINDOWSNT
return w32_get_internal_run_time ();
diff --git a/src/systime.h b/src/systime.h
index 75088bd4a6..419da80826 100644
--- a/src/systime.h
+++ b/src/systime.h
@@ -86,7 +86,10 @@ timespec_valid_p (struct timespec t)
/* defined in timefns.c */
extern struct timeval make_timeval (struct timespec) ATTRIBUTE_CONST;
+extern Lisp_Object make_lisp_realtime (struct timespec);
extern Lisp_Object make_lisp_time (struct timespec);
+extern Lisp_Object make_lisp_time_clockres (struct timespec, Lisp_Object,
+ long int, long int);
extern Lisp_Object timespec_to_lisp (struct timespec);
extern bool list4_to_timespec (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, struct timespec *);
diff --git a/src/timefns.c b/src/timefns.c
index 3f8efadf54..0d0a8a5922 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -77,12 +77,17 @@ Copyright (C) 1985-1987, 1989, 1993-2022 Free Software Foundation, Inc.
enum { CURRENT_TIME_LIST = true };
#endif
+/* Clock resolution of struct timespec. */
#if FIXNUM_OVERFLOW_P (1000000000)
static Lisp_Object timespec_hz;
#else
# define timespec_hz make_fixnum (TIMESPEC_HZ)
#endif
+/* Clock resolution of realtime, in various forms. HZ*RES == TIMESPEC_HZ. */
+static Lisp_Object realtime_lisphz;
+static long int realtime_hz, realtime_res;
+
#define TRILLION 1000000000000
#if FIXNUM_OVERFLOW_P (TRILLION)
static Lisp_Object trillion;
@@ -302,9 +307,24 @@ tzlookup (Lisp_Object zone, bool settz)
return new_tz;
}
+static void
+init_time_res (void)
+{
+ realtime_res = gettime_res ();
+ eassume (0 < realtime_res);
+ if (TIMESPEC_HZ < realtime_res)
+ realtime_res = TIMESPEC_HZ;
+ realtime_hz = TIMESPEC_HZ / realtime_res;
+ realtime_lisphz = make_int (realtime_hz);
+}
+
void
init_timefns (void)
{
+ pdumper_do_now_and_after_load (init_time_res);
+ if (FIXNUM_OVERFLOW_P (TIMESPEC_HZ) && !initialized)
+ staticpro (&realtime_lisphz);
+
#ifdef HAVE_UNEXEC
/* A valid but unlikely setting for the TZ environment variable.
It is OK (though a bit slower) if the user chooses this value. */
@@ -589,7 +609,7 @@ timespec_to_lisp (struct timespec t)
/* Convert T to a Lisp timestamp, assuming a LISPHZ or HZ-frequency
clock with resolution RES ns (so that HZ*RES = TIMESPEC_HZ). */
-static Lisp_Object
+Lisp_Object
make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz,
long int hz, long int res)
{
@@ -604,13 +624,23 @@ make_lisp_time_clockres (struct timespec t, Lisp_Object lisphz,
return timespec_clockres_to_lisp (t, lisphz, hz, res);
}
-/* Convert T to a Lisp timestamp. */
+/* Convert T to a Lisp timestamp, assuming full resolution. */
Lisp_Object
make_lisp_time (struct timespec t)
{
return make_lisp_time_clockres (t, timespec_hz, TIMESPEC_HZ, 1);
}
+/* Convert T to a Lisp timestamp, assuming gettime resolution. */
+Lisp_Object
+make_lisp_realtime (struct timespec t)
+{
+ if (NILP (realtime_lisphz))
+ abort ();
+ return make_lisp_time_clockres (t, realtime_lisphz,
+ realtime_hz, realtime_res);
+}
+
/* Return NUMERATOR / DENOMINATOR, rounded to the nearest double.
Arguments must be Lisp integers, and DENOMINATOR must be positive. */
static double
@@ -1799,7 +1829,7 @@ DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
the current time in seconds. */)
(void)
{
- return make_lisp_time (current_timespec ());
+ return make_lisp_realtime (current_timespec ());
}
DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string,
--
2.35.1
[-- Attachment #6: 0005-Support-format-time-string-N-like-date.patch --]
[-- Type: text/x-patch, Size: 7510 bytes --]
From 2a8467a5c48a5b7296bce13ccaee01fb80b53704 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:27 -0700
Subject: [PATCH 5/6] =?UTF-8?q?Support=20format-time-string=20%-N=20like?=
=?UTF-8?q?=20=E2=80=98date=E2=80=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
format-time-string now supports "%-N" to mean "do not pad past
timestamp resolution". This is compatible with GNU 'date'.
* src/timefns.c (hz_width, replace_percent_minus_N): New functions.
(Fformat_time_string): Use them to support %-N.
* test/src/timefns-tests.el (format-time-string-%-N): New test.
(format-time-string-padding-minimal-deletes-unneeded-zeros):
Adjust test to match new behavior.
---
doc/lispref/os.texi | 3 +++
etc/NEWS | 5 ++++
src/timefns.c | 53 +++++++++++++++++++++++++++++++++++----
test/src/timefns-tests.el | 12 +++++++--
4 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index bfcd51318e..30ece4aeff 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1897,6 +1897,9 @@ Time Parsing
@samp{_} pads with blanks, @samp{-}
suppresses padding, @samp{^} upper-cases letters, and @samp{#}
reverses the case of letters.
+As a special case, @samp{%-N} suppresses padding past the resolution
+of @var{time}. For example, if @var{time} is @code{(12345020 . 1000)},
+@samp{%-N} stands for @samp{020}.
You can also specify the field width and type of padding for any of
these @samp{%}-sequences. This works as in @code{printf}: you write
diff --git a/etc/NEWS b/etc/NEWS
index 38317fef03..d9635cce46 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1956,6 +1956,11 @@ For example, the macOS system clock resolution is 1 μs so
(time-convert nil t) now acts like (time-convert nil 1000000).
Formerly, time-convert used a clock resolution of 1 ns regardless.
++++
+** 'format-time-string' no longer pads %-N excessively.
+Insteads, it pads to the resolution of the timestamp when the
+timestamp resolution is greater than 1 ns.
+
+++
** 'encode-time' now also accepts a 6-element list with just time and date.
(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR)) is now short for
diff --git a/src/timefns.c b/src/timefns.c
index 0d0a8a5922..a6cc9c9f05 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -1430,6 +1430,42 @@ format_time_string (char const *format, ptrdiff_t formatlen,
return result;
}
+/* Yield the number of decimal digits needed to output a time with the
+ clock frequency HZ (0 < HZ <= TIMESPEC_HZ / 10), without losing info.
+ But if HZ is 1, yield 1. 0 < result < LOG10_TIMESPEC_HZ. */
+
+static int
+hz_width (int hz)
+{
+ int i = 0;
+ for (int r = 1; r < hz; r *= 10)
+ i++;
+ return i | !i;
+}
+
+/* Modify FORMAT, of length FORMATLEN and with FORMAT[FORMATLEN] == '\0',
+ in place, replacing each "%-N" with "%9N", "%6N", or whatever
+ number of digits is appropriate for min (HZ, TIMESPEC_HZ).
+ HZ is a positive integer. */
+
+static void
+replace_percent_minus_N (char *format, ptrdiff_t formatlen, Lisp_Object hz)
+{
+ for (char *f = format; f < format + formatlen; f++)
+ if (f[0] == '%')
+ {
+ if (f[1] == '-' && f[2] == 'N')
+ {
+ f[1] = (FIXNUMP (hz) && XFIXNUM (hz) <= TIMESPEC_HZ / 10
+ ? '0' + hz_width (XFIXNUM (hz))
+ : '9');
+ f += 2;
+ }
+ else
+ f += f[1] == '%';
+ }
+}
+
DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
doc: /* Use FORMAT-STRING to format the time value TIME.
A time value that is omitted or nil stands for the current time,
@@ -1484,7 +1520,7 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
A %-sequence can contain optional flags, field width, and a modifier
(in that order) after the `%'. The flags are:
-`-' Do not pad the field.
+`-' Do not pad the field. %-N means to not pad past TIME's resolution.
`_' Pad with spaces.
`0' Pad with zeros.
`+' Pad with zeros and put `+' before nonnegative year numbers with >4 digits.
@@ -1508,14 +1544,21 @@ DEFUN ("format-time-string", Fformat_time_string, Sformat_time_string, 1, 3, 0,
usage: (format-time-string FORMAT-STRING &optional TIME ZONE) */)
(Lisp_Object format_string, Lisp_Object timeval, Lisp_Object zone)
{
- struct timespec t = lisp_time_argument (timeval);
+ struct lisp_time lt = lisp_time_struct (timeval, 0);
+ struct timespec t = lisp_to_timespec (lt);
+ if (! timespec_valid_p (t))
+ time_overflow ();
struct tm tm;
- CHECK_STRING (format_string);
+ /* Convert FORMAT_STRING to the locale's encoding, and modify
+ any %-N formats in the copy to be the system clock resolution. */
format_string = code_convert_string_norecord (format_string,
Vlocale_coding_system, 1);
- return format_time_string (SSDATA (format_string), SBYTES (format_string),
- t, zone, &tm);
+ char *format = SSDATA (format_string);
+ ptrdiff_t formatlen = SBYTES (format_string);
+ replace_percent_minus_N (format, formatlen, lt.hz);
+
+ return format_time_string (format, formatlen, t, zone, &tm);
}
DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 3, 0,
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index 08d06f27d9..0d79152f8a 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -128,7 +128,7 @@ format-time-string-with-bignum-on-32-bit
(ert-deftest format-time-string-padding-minimal-deletes-unneeded-zeros ()
(let ((ref-time (encode-time '((123450 . 1000000) 0 0 15 2 2000 - - t))))
(should (equal (format-time-string "%-:::z" ref-time "FJT-12") "+12"))
- (should (equal (format-time-string "%-N" ref-time t) "12345"))
+ (should (equal (format-time-string "%-N" ref-time t) "123450"))
(should (equal (format-time-string "%-6N" ref-time t) "12345"))
(should (equal (format-time-string "%-m" ref-time t) "2")))) ;not "02"
@@ -137,7 +137,7 @@ format-time-string-padding-minimal-retains-needed-zeros
(should (equal (format-time-string "%-z" ref-time "IST-5:30") "+530"))
(should (equal (format-time-string "%-4z" ref-time "IST-5:30") "+530"))
(should (equal (format-time-string "%4z" ref-time "IST-5:30") "+530"))
- (should (equal (format-time-string "%-N" ref-time t) "00345"))
+ (should (equal (format-time-string "%-N" ref-time t) "003450"))
(should (equal (format-time-string "%-3N" ref-time t) "003"))
(should (equal (format-time-string "%3N" ref-time t) "003"))
(should (equal (format-time-string "%-m" ref-time t) "10")) ;not "1"
@@ -165,6 +165,14 @@ format-time-string-padding-zeros-adds-on-insignificant-side
(should (equal (format-time-string "%9N" ref-time t) "123000000"))
(should (equal (format-time-string "%6N" ref-time t) "123000"))))
+(ert-deftest format-time-string-%-N ()
+ (should (equal (format-time-string "%-N" '(0 . 10)) "0"))
+ (should (equal (format-time-string "%-N" '(0 . 11)) "00"))
+ (should (equal (format-time-string "%-N" '(0 . 100)) "00"))
+ (should (equal (format-time-string "%-N" '(0 . 101)) "000"))
+ (should (equal (format-time-string "%-N" '(0 . 100000000)) "00000000"))
+ (should (equal (format-time-string "%-N" '(0 . 100000001)) "000000000"))
+ (should (equal (format-time-string "%-N" '(0 . 1000000000)) "000000000")))
(ert-deftest time-equal-p-nil-nil ()
(should (time-equal-p nil nil)))
--
2.35.1
[-- Attachment #7: 0006-Use-TICKS-.-HZ-for-current-time-etc.patch --]
[-- Type: text/x-patch, Size: 6915 bytes --]
From c8b1fbb36aa0dee050dd7eea5fed9760c410a541 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 18 Apr 2022 13:08:27 -0700
Subject: [PATCH 6/6] Use (TICKS . HZ) for current-time etc.
* src/timefns.c (CURRENT_TIME_LIST): Change default to false.
All documentation changed.
---
doc/lispintro/emacs-lisp-intro.texi | 6 +++---
doc/lispref/files.texi | 14 +++++++-------
doc/lispref/intro.texi | 2 +-
doc/lispref/os.texi | 15 +++++++--------
etc/NEWS | 8 ++++++++
src/timefns.c | 26 ++++++++++++--------------
6 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi
index 466d7f0e60..afaed10cdf 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -15343,9 +15343,9 @@ Files List
100
@end group
@group
-(20615 27034 579989 697000)
-(17905 55681 0 0)
-(20615 26327 734791 805000)
+(1351051674579989697 . 1000000000)
+(1173477761000000000 . 1000000000)
+(1351050967734791805 . 1000000000)
13188
"-rw-r--r--"
@end group
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index d8b55b114a..4394f64a32 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -1423,9 +1423,9 @@ File Attributes
@group
(file-attributes "files.texi" 'string)
@result{} (nil 1 "lh" "users"
- (20614 64019 50040 152000)
- (20000 23 0 0)
- (20614 64555 902289 872000)
+ (1351023123050040152 . 1000000000)
+ (1310720023000000000 . 1000000000)
+ (1351023659902289872 . 1000000000)
122295 "-rw-rw-rw-"
t 6473924464520138
1014478468)
@@ -1449,13 +1449,13 @@ File Attributes
@item "users"
is in the group with name @samp{users}.
-@item (20614 64019 50040 152000)
+@item (1351023123050040152 . 1000000000)
was last accessed on October 23, 2012, at 20:12:03.050040152 UTC.
-@item (20000 23 0 0)
-was last modified on July 15, 2001, at 08:53:43 UTC.
+@item (1310720023000000000 . 1000000000)
+was last modified on July 15, 2001, at 08:53:43.000000000 UTC.
-@item (20614 64555 902289 872000)
+@item (1351023659902289872 . 1000000000)
last had its status changed on October 23, 2012, at 20:20:59.902289872 UTC.
@item 122295
diff --git a/doc/lispref/intro.texi b/doc/lispref/intro.texi
index 5afd2f4ecf..d1a3fef7a4 100644
--- a/doc/lispref/intro.texi
+++ b/doc/lispref/intro.texi
@@ -503,7 +503,7 @@ Version Info
@example
@group
emacs-build-time
- @result{} (20614 63694 515336 438000)
+ @result{} (1650228902637038831 . 1000000000)
@end group
@end example
@end defvar
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 30ece4aeff..ae551b0f71 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1359,9 +1359,6 @@ Time of Day
@tex
$high \times 2^{16} + low + micro \times 10^{-6} + pico \times 10^{-12}$.
@end tex
-In some cases, functions may default to returning two- or
-three-element lists, with omitted @var{micro} and @var{pico}
-components defaulting to zero.
On all current machines @var{pico} is a multiple of 1000, but this
may change as higher-resolution clocks become available.
@end itemize
@@ -1415,11 +1412,13 @@ Time of Day
@defun current-time
This function returns the current time as a Lisp timestamp.
-Although the timestamp takes the form @code{(@var{high} @var{low}
-@var{micro} @var{pico})} in the current Emacs release, this is
-planned to change in a future Emacs version. You can use the
-@code{time-convert} function to convert a timestamp to some other
-form. @xref{Time Conversion}.
+The timestamp has the form @code{(@var{ticks} . @var{hz})} where
+@var{ticks} counts clock ticks and @var{hz} is the clock ticks per second.
+
+In Emacs 28 and earlier, the returned timestamp had the list form
+@code{(@var{high} @var{low} @var{usec} @var{psec})}. You can use
+@code{(time-convert nil 'list)} to return the current time in this
+older form. @xref{Time Conversion}.
@end defun
@defun float-time &optional time
diff --git a/etc/NEWS b/etc/NEWS
index d9635cce46..c0b44effc6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -202,6 +202,14 @@ speakers of the Tamil language. To get back the previous behavior,
use the new 'tamil-itrans-digits' and 'tamil-inscript-digits' input
methods instead.
++++
+** current-time and related functions now yield (TICKS . HZ) timestamps.
+Previously they yielded timestamps of the forms (HI LO US PS), (HI LO
+US) or (HI LO), which were less regular and less efficient and which
+lacked information about clock resolution. This long-planned change
+was documented in Emacs 27. To convert a timestamp X to the old
+4-element list form, you can use (time-convert X 'list).
+
\f
* Changes in Emacs 29.1
diff --git a/src/timefns.c b/src/timefns.c
index a6cc9c9f05..286d5eb2b8 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -69,12 +69,11 @@ Copyright (C) 1985-1987, 1989, 1993-2022 Free Software Foundation, Inc.
# define FASTER_TIMEFNS 1
#endif
-/* Although current-time etc. generate list-format timestamps
- (HI LO US PS), the plan is to change these functions to generate
- frequency-based timestamps (TICKS . HZ) in a future release.
- To try this now, compile with -DCURRENT_TIME_LIST=0. */
+/* current-time etc. generate (TICKS . HZ) timestamps.
+ To change that to the old 4-element list format (HI LO US PS),
+ compile with -DCURRENT_TIME_LIST=1. */
#ifndef CURRENT_TIME_LIST
-enum { CURRENT_TIME_LIST = true };
+enum { CURRENT_TIME_LIST = false };
#endif
/* Clock resolution of struct timespec. */
@@ -1861,15 +1860,14 @@ DEFUN ("time-convert", Ftime_convert, Stime_convert, 1, 2, 0,
DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00.
-The time is returned as a list of integers (HIGH LOW USEC PSEC).
-HIGH has the most significant bits of the seconds, while LOW has the
-least significant 16 bits. USEC and PSEC are the microsecond and
-picosecond counts.
-
-In a future Emacs version, the format of the returned timestamp is
-planned to change. Use `time-convert' if you need a particular
-timestamp form; for example, (time-convert nil \\='integer) returns
-the current time in seconds. */)
+The time is returned as a pair of integers (TICKS . HZ), where TICKS
+counts clock ticks and HZ is the clock ticks per second.
+
+In Emacs 28 and earlier, the returned timestamp had the form (HIGH LOW
+USEC PSEC), where HIGH is the most significant bits of the seconds,
+LOW the least significant 16 bits, and USEC and PSEC are the
+microsecond and picosecond counts. Use \(time-convert nil \\='list)
+if you need this older timestamp form. */)
(void)
{
return make_lisp_realtime (current_timespec ());
--
2.35.1
next prev parent reply other threads:[~2022-04-19 2:09 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-07 12:37 bug#54764: encode-time: make DST and TIMEZONE fields of the list argument optional ones Max Nikulin
2022-04-09 7:52 ` Paul Eggert
2022-04-10 3:57 ` Max Nikulin
2022-04-13 14:40 ` Max Nikulin
2022-04-13 18:35 ` Paul Eggert
2022-04-14 13:19 ` Max Nikulin
2022-04-14 22:46 ` Paul Eggert
2022-04-15 2:14 ` Tim Cross
2022-04-15 17:23 ` Max Nikulin
2022-04-16 19:23 ` Paul Eggert
2022-04-21 16:59 ` Max Nikulin
2022-04-19 2:02 ` Paul Eggert [this message]
2022-04-19 5:50 ` Eli Zaretskii
2022-04-19 22:22 ` Paul Eggert
2022-04-20 7:23 ` Eli Zaretskii
2022-04-20 18:19 ` Paul Eggert
2022-04-20 18:41 ` Eli Zaretskii
2022-04-20 19:01 ` Paul Eggert
2022-04-20 19:14 ` Eli Zaretskii
2022-04-20 19:23 ` Paul Eggert
2022-04-20 19:30 ` Eli Zaretskii
2022-04-21 0:11 ` Paul Eggert
2022-04-21 6:44 ` Eli Zaretskii
2022-04-21 23:56 ` Paul Eggert
2022-04-22 5:01 ` Eli Zaretskii
2022-04-23 14:35 ` Bernhard Voelker
2022-04-20 15:07 ` Max Nikulin
2022-04-20 18:29 ` Paul Eggert
2022-04-25 15:30 ` Max Nikulin
2022-04-25 15:37 ` Paul Eggert
2022-04-25 19:49 ` Paul Eggert
2022-04-30 11:22 ` Max Nikulin
2022-05-01 2:32 ` Paul Eggert
2022-05-01 17:15 ` Max Nikulin
2022-04-13 15:12 ` Max Nikulin
2022-04-16 16:26 ` Max Nikulin
2022-04-17 1:58 ` Paul Eggert
2022-04-20 16:56 ` Max Nikulin
2022-04-20 19:17 ` Paul Eggert
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
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f9d9d26c-1974-b52a-8f4d-49167676c102@cs.ucla.edu \
--to=eggert@cs.ucla.edu \
--cc=54764@debbugs.gnu.org \
--cc=emacs-orgmode@gnu.org \
--cc=manikulin@gmail.com \
/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.
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).