Function: org-closest-date
org-closest-date is a byte-compiled function defined in org.el.gz.
Signature
(org-closest-date START CURRENT PREFER)
Documentation
Return closest date to CURRENT starting from START.
CURRENT and START are both time stamps.
When PREFER is past, return a date that is either CURRENT or
past. When PREFER is future, return a date that is either
CURRENT or future.
Only time stamps with a repeater are modified. Any other time stamp stay unchanged. In any case, return value is an absolute day number.
Source Code
;; Defined in /usr/src/emacs/lisp/org/org.el.gz
(defun org-closest-date (start current prefer)
"Return closest date to CURRENT starting from START.
CURRENT and START are both time stamps.
When PREFER is `past', return a date that is either CURRENT or
past. When PREFER is `future', return a date that is either
CURRENT or future.
Only time stamps with a repeater are modified. Any other time
stamp stay unchanged. In any case, return value is an absolute
day number."
(if (not (string-match "\\+\\([0-9]+\\)\\([hdwmy]\\)" start))
;; No repeater. Do not shift time stamp.
(time-to-days (org-time-string-to-time start))
(let ((value (string-to-number (match-string 1 start)))
(type (match-string 2 start)))
(if (= 0 value)
;; Repeater with a 0-value is considered as void.
(time-to-days (org-time-string-to-time start))
(let* ((base (org-date-to-gregorian start))
(target (org-date-to-gregorian current))
(sday (calendar-absolute-from-gregorian base))
(cday (calendar-absolute-from-gregorian target))
n1 n2)
;; If START is already past CURRENT, just return START.
(if (<= cday sday) sday
;; Compute closest date before (N1) and closest date past
;; (N2) CURRENT.
(pcase type
("h"
(let ((missing-hours
(mod (+ (- (* 24 (- cday sday))
(nth 2 (org-parse-time-string start)))
org-extend-today-until)
value)))
(setf n1 (if (= missing-hours 0) cday
(- cday (1+ (/ missing-hours 24)))))
(setf n2 (+ cday (/ (- value missing-hours) 24)))))
((or "d" "w")
(let ((value (if (equal type "w") (* 7 value) value)))
(setf n1 (+ sday (* value (/ (- cday sday) value))))
(setf n2 (+ n1 value))))
("m"
(let* ((add-months
(lambda (d n)
;; Add N months to gregorian date D, i.e.,
;; a list (MONTH DAY YEAR). Return a valid
;; gregorian date.
(let ((m (+ (nth 0 d) n)))
(list (mod m 12)
(nth 1 d)
(+ (/ m 12) (nth 2 d))))))
(months ; Complete months to TARGET.
(* (/ (+ (* 12 (- (nth 2 target) (nth 2 base)))
(- (nth 0 target) (nth 0 base))
;; If START's day is greater than
;; TARGET's, remove incomplete month.
(if (> (nth 1 target) (nth 1 base)) 0 -1))
value)
value))
(before (funcall add-months base months)))
(setf n1 (calendar-absolute-from-gregorian before))
(setf n2
(calendar-absolute-from-gregorian
(funcall add-months before value)))))
(_
(let* ((d (nth 1 base))
(m (nth 0 base))
(y (nth 2 base))
(years ; Complete years to TARGET.
(* (/ (- (nth 2 target)
y
;; If START's month and day are
;; greater than TARGET's, remove
;; incomplete year.
(if (or (> (nth 0 target) m)
(and (= (nth 0 target) m)
(> (nth 1 target) d)))
0
1))
value)
value))
(before (list m d (+ y years))))
(setf n1 (calendar-absolute-from-gregorian before))
(setf n2 (calendar-absolute-from-gregorian
(list m d (+ (nth 2 before) value)))))))
;; Handle PREFER parameter, if any.
(cond
((eq prefer 'past) (if (= cday n2) n2 n1))
((eq prefer 'future) (if (= cday n1) n1 n2))
(t (if (> (abs (- cday n1)) (abs (- cday n2))) n2 n1)))))))))