… is modeled as the function
\[\begin{equation*} f : D \to T, \end{equation*} \]
where | \(d \in D\) | is the exercise day, |
measured in \(24\)-hour days from the Unix epoch; and | ||
\(t > 0 \in T\) | is the total exercise duration on day \(d\), | |
measured in seconds. |
\(f\) is computed, as a hash table, from Org Clock data by
(defun my-exercise-log () "Return a hash map with exercise durations per day." (let ((lexical-binding t)) (save-excursion (org-id-goto my-exercise-id) (goto-char (org-log-beginning)) (named-let recur ((days (make-hash-table :test 'equal))) (let ((element (org-element-at-point-no-context))) (if (eq 'clock (org-element-type element)) (let* ((day (org-element-property :value element)) (day (org-format-timestamp day "%s")) (day (string-to-number day)) (day (/ (float day) 60 60 24)) (time (org-element-property :duration element)) (time (org-duration-to-minutes time)) (time (* time 60))) (puthash day (+ (gethash day days 0) time) days) (org-forward-element) (recur days)) days))))))
where the ‘my-exercise-id’ is
(defcustom my-exercise-id "0DB14413-C66D-41F6-A6C0-17F433F0B740" "ID of the Org heading on which all exercises are clocked.")
… is the total count of exercise days
\[\begin{equation*} \sum_{d \in D} 1 = |D| = \boxed{591} ~ \text{days} \thinspace, \end{equation*} \]
computed by
(defun my-total-exercise-days () (hash-table-count (my-exercise-log)))
… is the sum of all exercise durations
\[\begin{equation*} \frac{\sum_{d \in D} f(d)}{60 \cdot 60} \approx \boxed{422.82} \, \text{hours}, \end{equation*} \]
computed by
(defun my-total-exercise-hours () "Return the sum of all exercise durations in hours." (format "%0.2f" (/ (let ((total-duration 0)) (maphash (lambda (day duration) (setq total-duration (+ total-duration duration))) (my-exercise-log)) total-duration) (* 60 60))))
… is the artihmetic mean of all exercise durations
\[\begin{equation*} \frac{\sum_{d \in D} f(d)}{60 \thinspace |D|} \approx \boxed{42.93} \, \text{minutes}, \end{equation*} \]
computed by
(defun my-average-exercise-duration () "Return the average exercise duration in minutes." (let ((log (my-exercise-log))) (format "%0.2f" (/ (let ((total-duration 0)) (maphash (lambda (day duration) (setq total-duration (+ total-duration duration))) log) total-duration) (* 60 (hash-table-count log))))))
… is derived from the earliest exercise day
\[\begin{equation*} \min D \approx 19386.958333333332 = \underbrace{\> \text{2023-01-30} \>} _{\substack{\text{ISO 8601} \\ \text{date}}} \end{equation*} \]
computed by
(defun my-exercise-anniversary-date () (format-time-string "%Y-%m-%d" (* (my-exercise-anniversary) 24 60 60)))
(defun my-exercise-anniversary () (let ((anniversary nil)) (maphash (lambda (day _) (when (or (not anniversary) (< day anniversary)) (setq anniversary day))) (my-exercise-log)) anniversary))
The Org Agenda anniversary is computed by
(defun my-exercise-org-anniversary () (interactive) (format (concat "%%%%(org-anniversary %s)" " /me starts exercising, %%d year(s) ago") (format-time-string "%Y %m %d" (* (my-exercise-anniversary) 24 60 60))))