org-duration-from-minutes: Accept negative durations
* lisp/org-duration.el (org-duration-from-minutes): Allow MINUTES argument to be negative. Reported-by: Raffael Stocker <r.stocker@mnet-mail.de> Link: https://orgmode.org/list/yplmzfsrqjw6.fsf@mnet-mail.de
This commit is contained in:
parent
288c7069c4
commit
ee58259bc7
|
@ -324,109 +324,110 @@ When optional argument CANONICAL is non-nil, ignore
|
||||||
`org-duration-units' and use standard time units value.
|
`org-duration-units' and use standard time units value.
|
||||||
|
|
||||||
Raise an error if expected format is unknown."
|
Raise an error if expected format is unknown."
|
||||||
(pcase (or fmt org-duration-format)
|
(if (< minutes 0) (concat "-" (org-duration-from-minutes (abs minutes) fmt canonical))
|
||||||
(`h:mm
|
(pcase (or fmt org-duration-format)
|
||||||
(format "%d:%02d" (/ minutes 60) (mod minutes 60)))
|
(`h:mm
|
||||||
(`h:mm:ss
|
(format "%d:%02d" (/ minutes 60) (mod minutes 60)))
|
||||||
(let* ((whole-minutes (floor minutes))
|
(`h:mm:ss
|
||||||
(seconds (mod (* 60 minutes) 60)))
|
(let* ((whole-minutes (floor minutes))
|
||||||
(format "%s:%02d"
|
(seconds (mod (* 60 minutes) 60)))
|
||||||
(org-duration-from-minutes whole-minutes 'h:mm)
|
(format "%s:%02d"
|
||||||
seconds)))
|
(org-duration-from-minutes whole-minutes 'h:mm)
|
||||||
((pred atom) (error "Invalid duration format specification: %S" fmt))
|
seconds)))
|
||||||
;; Mixed format. Call recursively the function on both parts.
|
((pred atom) (error "Invalid duration format specification: %S" fmt))
|
||||||
((and duration-format
|
;; Mixed format. Call recursively the function on both parts.
|
||||||
(let `(special . ,(and mode (or `h:mm:ss `h:mm)))
|
((and duration-format
|
||||||
(assq 'special duration-format)))
|
(let `(special . ,(and mode (or `h:mm:ss `h:mm)))
|
||||||
(let* ((truncated-format
|
(assq 'special duration-format)))
|
||||||
;; Remove "special" mode from duration format in order to
|
(let* ((truncated-format
|
||||||
;; recurse properly. Also remove units smaller or equal
|
;; Remove "special" mode from duration format in order to
|
||||||
;; to an hour since H:MM part takes care of it.
|
;; recurse properly. Also remove units smaller or equal
|
||||||
(cl-remove-if-not
|
;; to an hour since H:MM part takes care of it.
|
||||||
(lambda (pair)
|
(cl-remove-if-not
|
||||||
(pcase pair
|
(lambda (pair)
|
||||||
(`(,(and unit (pred stringp)) . ,_)
|
(pcase pair
|
||||||
(> (org-duration--modifier unit canonical) 60))
|
(`(,(and unit (pred stringp)) . ,_)
|
||||||
(_ nil)))
|
(> (org-duration--modifier unit canonical) 60))
|
||||||
duration-format))
|
(_ nil)))
|
||||||
(min-modifier ;smallest modifier above hour
|
duration-format))
|
||||||
(and truncated-format
|
(min-modifier ;smallest modifier above hour
|
||||||
(apply #'min
|
(and truncated-format
|
||||||
(mapcar (lambda (p)
|
(apply #'min
|
||||||
(org-duration--modifier (car p) canonical))
|
(mapcar (lambda (p)
|
||||||
truncated-format)))))
|
(org-duration--modifier (car p) canonical))
|
||||||
(if (or (null min-modifier) (< minutes min-modifier))
|
truncated-format)))))
|
||||||
;; There is not unit above the hour or the smallest unit
|
(if (or (null min-modifier) (< minutes min-modifier))
|
||||||
;; above the hour is too large for the number of minutes we
|
;; There is not unit above the hour or the smallest unit
|
||||||
;; need to represent. Use H:MM or H:MM:SS syntax.
|
;; above the hour is too large for the number of minutes we
|
||||||
(org-duration-from-minutes minutes mode canonical)
|
;; need to represent. Use H:MM or H:MM:SS syntax.
|
||||||
;; Represent minutes above hour using provided units and H:MM
|
(org-duration-from-minutes minutes mode canonical)
|
||||||
;; or H:MM:SS below.
|
;; Represent minutes above hour using provided units and H:MM
|
||||||
(let* ((units-part (* min-modifier (/ (floor minutes) min-modifier)))
|
;; or H:MM:SS below.
|
||||||
(minutes-part (- minutes units-part))
|
(let* ((units-part (* min-modifier (/ (floor minutes) min-modifier)))
|
||||||
(compact (memq 'compact duration-format)))
|
(minutes-part (- minutes units-part))
|
||||||
(concat
|
(compact (memq 'compact duration-format)))
|
||||||
(org-duration-from-minutes units-part truncated-format canonical)
|
(concat
|
||||||
(and (not compact) " ")
|
(org-duration-from-minutes units-part truncated-format canonical)
|
||||||
(org-duration-from-minutes minutes-part mode))))))
|
(and (not compact) " ")
|
||||||
;; Units format.
|
(org-duration-from-minutes minutes-part mode))))))
|
||||||
(duration-format
|
;; Units format.
|
||||||
(let* ((fractional
|
(duration-format
|
||||||
(let ((digits (cdr (assq 'special duration-format))))
|
(let* ((fractional
|
||||||
(and digits
|
(let ((digits (cdr (assq 'special duration-format))))
|
||||||
(or (wholenump digits)
|
(and digits
|
||||||
(error "Unknown formatting directive: %S" digits))
|
(or (wholenump digits)
|
||||||
(format "%%.%df" digits))))
|
(error "Unknown formatting directive: %S" digits))
|
||||||
(selected-units
|
(format "%%.%df" digits))))
|
||||||
(sort (cl-remove-if
|
(selected-units
|
||||||
;; Ignore special format cells and compact option.
|
(sort (cl-remove-if
|
||||||
(lambda (pair)
|
;; Ignore special format cells and compact option.
|
||||||
(pcase pair
|
(lambda (pair)
|
||||||
((or `compact `(special . ,_)) t)
|
(pcase pair
|
||||||
(_ nil)))
|
((or `compact `(special . ,_)) t)
|
||||||
duration-format)
|
(_ nil)))
|
||||||
(lambda (a b)
|
duration-format)
|
||||||
(> (org-duration--modifier (car a) canonical)
|
(lambda (a b)
|
||||||
(org-duration--modifier (car b) canonical)))))
|
(> (org-duration--modifier (car a) canonical)
|
||||||
(separator (if (memq 'compact duration-format) "" " ")))
|
(org-duration--modifier (car b) canonical)))))
|
||||||
(cond
|
(separator (if (memq 'compact duration-format) "" " ")))
|
||||||
;; Fractional duration: use first unit that is either required
|
(cond
|
||||||
;; or smaller than MINUTES.
|
;; Fractional duration: use first unit that is either required
|
||||||
(fractional
|
;; or smaller than MINUTES.
|
||||||
(let* ((unit (car
|
(fractional
|
||||||
(or (cl-find-if
|
(let* ((unit (car
|
||||||
(lambda (pair)
|
(or (cl-find-if
|
||||||
(pcase pair
|
(lambda (pair)
|
||||||
(`(,u . ,req?)
|
(pcase pair
|
||||||
(or req?
|
(`(,u . ,req?)
|
||||||
(<= (org-duration--modifier u canonical)
|
(or req?
|
||||||
minutes)))))
|
(<= (org-duration--modifier u canonical)
|
||||||
selected-units)
|
minutes)))))
|
||||||
;; Fall back to smallest unit.
|
selected-units)
|
||||||
(org-last selected-units))))
|
;; Fall back to smallest unit.
|
||||||
(modifier (org-duration--modifier unit canonical)))
|
(org-last selected-units))))
|
||||||
(concat (format fractional (/ (float minutes) modifier)) unit)))
|
(modifier (org-duration--modifier unit canonical)))
|
||||||
;; Otherwise build duration string according to available
|
(concat (format fractional (/ (float minutes) modifier)) unit)))
|
||||||
;; units.
|
;; Otherwise build duration string according to available
|
||||||
((org-string-nw-p
|
;; units.
|
||||||
(org-trim
|
((org-string-nw-p
|
||||||
(mapconcat
|
(org-trim
|
||||||
(lambda (units)
|
(mapconcat
|
||||||
(pcase-let* ((`(,unit . ,required?) units)
|
(lambda (units)
|
||||||
(modifier (org-duration--modifier unit canonical)))
|
(pcase-let* ((`(,unit . ,required?) units)
|
||||||
(cond ((<= modifier minutes)
|
(modifier (org-duration--modifier unit canonical)))
|
||||||
(let ((value (floor minutes modifier)))
|
(cond ((<= modifier minutes)
|
||||||
(cl-decf minutes (* value modifier))
|
(let ((value (floor minutes modifier)))
|
||||||
(format "%s%d%s" separator value unit)))
|
(cl-decf minutes (* value modifier))
|
||||||
(required? (concat separator "0" unit))
|
(format "%s%d%s" separator value unit)))
|
||||||
(t ""))))
|
(required? (concat separator "0" unit))
|
||||||
selected-units
|
(t ""))))
|
||||||
""))))
|
selected-units
|
||||||
;; No unit can properly represent MINUTES. Use the smallest
|
""))))
|
||||||
;; one anyway.
|
;; No unit can properly represent MINUTES. Use the smallest
|
||||||
(t
|
;; one anyway.
|
||||||
(pcase-let ((`((,unit . ,_)) (last selected-units)))
|
(t
|
||||||
(concat "0" unit))))))))
|
(pcase-let ((`((,unit . ,_)) (last selected-units)))
|
||||||
|
(concat "0" unit)))))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun org-duration-h:mm-only-p (times)
|
(defun org-duration-h:mm-only-p (times)
|
||||||
|
|
Loading…
Reference in New Issue