;; I noticed I've been doing a lot of work with time. This is time ;; helpers. (in-package #:cl-deck-builder2.toolkit.time) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun time-format (when &optional (format local-time:+rfc3339-format+)) (local-time:format-timestring nil when :format format)) (defun time-format/date-only (when) (time-format when local-time:+rfc3339-format/date-only+)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun day- (when &optional (amount 1)) "Subtract AMOUNT days from WHEN." (local-time:timestamp- when amount :day)) (defun day+ (when &optional (amount 1)) "Add AMOUNT days to WHEN." (local-time:timestamp+ when amount :day)) (defun month- (when &optional (amount 1)) "Subtract AMOUNT months from WHEN." (local-time:timestamp- (local-time:timestamp- when amount :month) local-time:+seconds-per-day+ :sec)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun time-now () "Today's date, passed through FORMAT-DMY." (local-time:now)) (defun time-yesterday () "Yesterday's date, passed through FORMAT-DMY." (day- (time-now))) ;; TODO Why am I using this? (defun time-first-of-month () "The first day of this month." (local-time:timestamp-minimize-part (time-now) :day)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun n-month-list (&key (when (time-now)) (start 1) (n 6)) "Produce a LIST of the last N months, using WHEN as the reference point. The values iterate numerically from START, that is, the result will be length N - START. The date will be on the first of each month, in chronological order." (mapcar (lambda (n) (month- when n)) (loop for i from start upto n collect i))) (defun n-day-list (&key (when (time-now)) (start 0) (n 5)) "Produce a LIST of the last N days, using WHEN as a reference point. The values will iterate numerically from START, that is, the result will be length N - START. The exact times will not be modified. The results will be in chronological order." (mapcar (lambda (n) (day- when n)) (loop for i from start upto n collect i))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun time-friday (&key (when (time-now))) (local-time:adjust-timestamp when (offset :day-of-week :friday))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun format-status-report (&key (stream *standard-output*) (when (time-friday))) (let ((date-str (time-format/date-only when)) (day-map (reverse (mapcar #'time-format/date-only (n-day-list :when when :n 4))))) (format stream "#+TITLE: Status Report: Week of ~A~%~%* Status Report: ~ Week of ~A~%~%Total hours: 40 h.~%~%~{** ~A~%~%Hours: 0800A-1600P (8h)~%~%~}" date-str date-str day-map))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defparameter *status-report-base-dir* (probe-file #P"~/code/cl-deck-builder2/doc/status-report/")) (defun generate-status-report (&key (when (time-friday))) (let ((filespec (merge-pathnames (format nil "~a.org" (time-format/date-only when)) *status-report-base-dir*))) (with-open-file (f filespec :direction :output :if-exists :error :if-does-not-exist :create) (format-status-report :stream f :when when) (probe-file filespec))))