Function: format-seconds
format-seconds is an autoloaded and byte-compiled function defined in
time-date.el.gz.
Signature
(format-seconds STRING SECONDS)
Documentation
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.
The "%x" specifier does not print anything. When it is used, specifiers must be given in order of decreasing size. To the right of "%x", trailing zero units are not output.
Probably introduced at or before Emacs version 23.1.
Aliases
org-format-seconds (obsolete since 9.0)
Source Code
;; Defined in /usr/src/emacs/lisp/calendar/time-date.el.gz
;;;###autoload
(defun format-seconds (string seconds)
"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.
The \"%x\" specifier does not print anything. When it is used,
specifiers must be given in order of decreasing size. To the
right of \"%x\", trailing zero units are not output."
(let ((start 0)
(units '(("y" "year" 31536000)
("d" "day" 86400)
("h" "hour" 3600)
("m" "minute" 60)
("s" "second" 1)
("z")
("x")))
(case-fold-search t)
spec match usedunits zeroflag larger prev name unit num
leading-zeropos trailing-zeropos fraction minus
chop-leading chop-trailing)
(while (string-match "%\\.?[0-9]*\\(,[0-9]\\)?\\(.\\)" string start)
(setq start (match-end 0)
spec (match-string 2 string))
(unless (string-equal spec "%")
(or (setq match (assoc (downcase spec) units))
(error "Bad format specifier: `%s'" spec))
(if (assoc (downcase spec) usedunits)
(error "Multiple instances of specifier: `%s'" spec))
(if (or (string-equal (car match) "z")
(string-equal (car match) "x"))
(setq zeroflag t)
(unless larger
(setq unit (nth 2 match)
larger (and prev (> unit prev))
prev unit)))
(push match usedunits)))
(when (and zeroflag larger)
(error "Units are not in decreasing order of size"))
(unless (numberp seconds)
(setq seconds (float-time seconds)))
(setq minus (when (< seconds 0) "-") ; Treat -0.0 like 0.0.
seconds (abs seconds)
seconds (let ((s (floor seconds)))
(setq fraction (- seconds s))
s))
(dolist (u units)
(setq spec (car u)
name (cadr u)
unit (nth 2 u))
(when (string-match
(format "%%\\(\\.?[0-9]+\\)?\\(,[0-9]+\\)?\\(%s\\)" spec)
string)
(cond
((string-equal spec "z")
(setq chop-leading
(if leading-zeropos
(min leading-zeropos (match-beginning 0))
;; The entire spec is zero, get past "%z" to last 0.
(+ 2 (match-beginning 0)))))
((string-equal spec "x")
(setq chop-trailing t))
(t
;; Cf article-make-date-line in gnus-art.
(setq num (floor seconds unit)
seconds (- seconds (* num unit)))
(let ((is-zero (zerop (if (= unit 1)
(+ num fraction)
num))))
;; Start position of the first non-zero unit.
(when (and (not leading-zeropos)
(not is-zero))
(setq leading-zeropos (match-beginning 0)))
(unless is-zero
(setq trailing-zeropos nil))
(when (and (not trailing-zeropos)
is-zero)
(setq trailing-zeropos (match-beginning 0))))
(setq string
(replace-match
(format (if (match-string 2 string)
(concat
"%"
(and (match-string 1 string)
(if (= (elt (match-string 1 string) 0) ?.)
(concat "0" (substring
(match-string 1 string) 1))
(match-string 1 string)))
(concat "." (substring
(match-string 2 string) 1))
"f%s")
(concat "%" (match-string 1 string) "d%s"))
(if (= unit 1)
(+ num fraction)
num)
(if (string-equal (match-string 3 string) spec)
"" ; lower-case, no unit-name
(format " %s%s" name
(if (= num 1) "" "s"))))
t t string))))))
(let ((pre string))
(when (and chop-trailing trailing-zeropos)
(setq string (substring string 0 trailing-zeropos)))
(when chop-leading
(setq string (substring string chop-leading)))
;; If we ended up removing everything, return the formatted
;; string in full.
(when (equal string "")
(setq string pre)))
(setq string (replace-regexp-in-string "%[zx]" "" string))
(concat minus (string-trim (string-replace "%%" "%" string)))))