1

Given two times (in the format returned by (current-time)), does Emacs have a way to convert this to a humanly readable delta?

Examples could include:

  • 3 days.
  • 2 weeks, 3 days.
  • 3 hours, 2 minutes.
  • tomorrow (possible alternative to 1 day)
  • yesterday (possible alternative to -1 day)

... etc.

4
  • What does "tomorrow" mean in this context? – NickD May 4 at 13:40
  • As an alternative to "1 day" it's just an example, "1 day" would also be acceptable. – ideasman42 May 4 at 13:49
  • That's only if one of the two times you mention in your title is now - right? – NickD May 4 at 13:53
  • Yes, it only makes sense if one time is current (so it could be an option to display relative times). – ideasman42 May 4 at 19:07
3

Here's one way:

(defun my-format-time-delta (time1 time2)
  "Return difference between TIME1 & TIME2 as a readable string."
  (format-seconds "%Y %D %H %M %z%S" (float-time (time-subtract time1 time2))))

This relies on the function format-seconds:

format-seconds is a compiled Lisp function in `time-date.el'.

(format-seconds STRING SECONDS)

  Probably introduced at or before Emacs version 23.1.

Use format control STRING to format the number SECONDS.
The valid format specifiers are:
%y is the number of (365-day) years.
%d is the number of days.
%h is the number of hours.
%m is the number of minutes.
%s is the number of seconds.
%z is a non-printing control flag (see below).
%% is a literal "%".

Upper-case specifiers are followed by the unit-name (e.g. "years").
Lower-case specifiers return only the unit.

"%" may be followed by a number specifying a width, with an
optional leading "." for zero-padding.  For example, "%.3Y" will
return something of the form "001 year".

The "%s" spec takes an additional optional parameter,
introduced by the "," character, to say how many decimals to
use.  "%,1s" means "use one decimal".

The "%z" specifier does not print anything.  When it is used, specifiers
must be given in order of decreasing size.  To the left of "%z", nothing
is output until the first non-zero unit is encountered.

Sample usage:

(mapconcat (lambda (delta)
             (let* ((now (current-time))
                    (then (time-subtract now delta)))
               (format "%9d => %s" delta (my-format-time-delta now then))))
           '(10 100 10000 100000 100000000)
           "\n")

;;        10 => 10 seconds
;;       100 => 1 minute 40 seconds
;;     10000 => 2 hours 46 minutes 40 seconds
;;    100000 => 1 day 3 hours 46 minutes 40 seconds
;; 100000000 => 3 years 62 days 9 hours 46 minutes 40 seconds

For more details, see:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.