Went back to milliseconds to benefit accuracy over formatting ease. Start and end timestamps for run splits are now based on internal timestamps as well.

This commit is contained in:
Logan Hunt 2022-06-02 22:38:43 -07:00
parent 5a18186254
commit 816ba3e427
Signed by untrusted user who does not match committer: simponic
GPG Key ID: 52B3774857EB24B1
3 changed files with 29 additions and 25 deletions

View File

@ -1,13 +1,14 @@
(mito:deftable run () (mito:deftable run ()
((category :col-type category)) ((category :col-type category)
(end-date :col-type (or :datetime :null)))
(:record-timestamps nil) (:record-timestamps nil)
(:conc-name run-)) (:conc-name run-))
(mito:deftable run-split () (mito:deftable run-split ()
((run :col-type run) ((run :col-type run)
(category-split :col-type category-split) (category-split :col-type category-split)
(start-time :col-type (or :datetime :null)) (start-timestamp :col-type (or :bigint :null))
(end-time :col-type (or :datetime :null))) (end-timestamp :col-type (or :bigint :null)))
(:record-timestamps nil) (:record-timestamps nil)
(:conc-name run-split-)) (:conc-name run-split-))
@ -21,22 +22,20 @@
;; Returns the elapsed time in milliseconds since split started to either ;; Returns the elapsed time in milliseconds since split started to either
;; current time or the split's end time ;; current time or the split's end time
(defun run-split-elapsed-time (run-split) (defun run-split-elapsed-time (run-split)
(let ((start (ignore-errors (run-split-start-time run-split))) (let ((start (ignore-errors (run-split-start-timestamp run-split)))
(end (or (ignore-errors (run-split-end-time run-split)) (local-time:now)))) (end (or (ignore-errors (run-split-end-timestamp run-split)) (get-internal-real-time))))
(if start (if start
(floor (* 100 (local-time:timestamp-difference end start)))))) (- end start))))
(defun run-split-format-elapsed-time (run-split) (defun run-split-format-elapsed-time (run-split)
(let ((elapsed (run-split-elapsed-time run-split))) (let ((elapsed (run-split-elapsed-time run-split)))
(if elapsed (if elapsed
(format-time (make-time-alist elapsed)) (format-time (make-time-alist (millis-since-internal-timestamp 0 elapsed)))
"-"))) "-")))
(defmacro query-with-runs-elapsed (&rest body) (defmacro query-with-runs-elapsed (&rest body)
`(mito:retrieve-by-sql `(mito:retrieve-by-sql
(sxql:select (:* (:as (:raw "sum(julianday(end_time) - julianday(start_time))*24*60*60") :elapsed)) (sxql:select (:* (:as (:sum (:* (:/ (:raw "end_timestamp - CAST(start_timestamp AS REAL)") ,internal-time-units-per-second) 1000)) :elapsed))
(sxql:from :run_split) (sxql:from :run_split)
(sxql:group-by :run_id) (sxql:group-by :run_id)
,@body))) ,@body)))

View File

@ -44,13 +44,14 @@
;; Updates the current total elapsed time of the speedrun if it's running ;; Updates the current total elapsed time of the speedrun if it's running
(defun update-time (speedrun) (defun update-time (speedrun)
(if (eq (speedrun-state speedrun) 'RUNNING) (if (eq (speedrun-state speedrun) 'RUNNING)
(setf (speedrun-elapsed speedrun) (floor (* 100 (/ (- (get-internal-real-time) (speedrun-start-timestamp speedrun)) internal-time-units-per-second)))))) (setf (speedrun-elapsed speedrun) (millis-since-internal-timestamp (speedrun-start-timestamp speedrun)))))
;; Initializes a speedrun to start running the timer ;; Initializes a speedrun to start running the timer
(defun start-speedrun (speedrun) (defun start-speedrun (speedrun)
(let ((now (get-internal-real-time)))
(setf (speedrun-state speedrun) 'RUNNING (setf (speedrun-state speedrun) 'RUNNING
(speedrun-start-timestamp speedrun) (get-internal-real-time) (speedrun-start-timestamp speedrun) now
(run-split-start-time (current-split speedrun)) (local-time:now))) (run-split-start-timestamp (current-split speedrun)) now)))
;; Saves the speedrun into the database ;; Saves the speedrun into the database
(defun save-speedrun (speedrun) (defun save-speedrun (speedrun)
@ -59,16 +60,18 @@
;; Set the state of the speedrun to be stopped if there are no more splits. ;; Set the state of the speedrun to be stopped if there are no more splits.
;; Or, set the current split to the next one in the list. ;; Or, set the current split to the next one in the list.
(defun next-split (speedrun) (defun next-split (speedrun)
(let ((now (local-time:now))) (let ((now (get-internal-real-time)))
(unless (equal (speedrun-state speedrun) 'STOPPED) (unless (equal (speedrun-state speedrun) 'STOPPED)
(setf (run-split-end-time (current-split speedrun)) now) (setf (run-split-end-timestamp (current-split speedrun)) now)
(if (equal (speedrun-current-split-index speedrun) (1- (length (speedrun-splits speedrun)))) (if (equal (speedrun-current-split-index speedrun) (1- (length (speedrun-splits speedrun))))
(progn (progn
(setf (setf
(speedrun-elapsed speedrun) (apply '+ (mapcar 'run-split-elapsed-time (speedrun-splits speedrun))) (run-end-date (speedrun-run-dao speedrun)) (local-time:now)
;; Since timer can get +-0.02 seconds out of sync of splits, just set it to the sum of the splits' elapsed
(speedrun-elapsed speedrun) (millis-since-internal-timestamp 0 (apply '+ (mapcar 'run-split-elapsed-time (speedrun-splits speedrun))))
(speedrun-state speedrun) 'STOPPED) (speedrun-state speedrun) 'STOPPED)
(save-speedrun speedrun)) (save-speedrun speedrun))
(progn (progn
(inc (speedrun-current-split-index speedrun)) (inc (speedrun-current-split-index speedrun))
(setf (run-split-start-time (current-split speedrun)) now)))))) (setf (run-split-start-timestamp (current-split speedrun)) now))))))

View File

@ -1,9 +1,11 @@
;; Makes a-list with '((hours . HOURS) (minutes . MINUTES) (seconds . SECONDS) (cs . CENTISECONDS)) (defun millis-since-internal-timestamp (start-timestamp &optional (end-timestamp (get-internal-real-time)))
(defun make-time-alist (cs) (ceiling (* 1000 (/ (- end-timestamp start-timestamp) internal-time-units-per-second))))
`((hours . ,(floor (/ cs (* 100 60 60))))
(minutes . ,(floor (mod (/ cs (* 100 60)) 60))) (defun make-time-alist (millis)
(seconds . ,(floor (mod (/ cs 100) 60))) `((hours . ,(floor (/ millis (* 1000 60 60))))
(cs . ,(mod cs 100)))) (minutes . ,(floor (mod (/ millis (* 1000 60)) 60)))
(seconds . ,(floor (mod (/ millis 1000) 60)))
(millis . ,(mod millis 1000))))
;; Formats, disregarding min/hour if they shouldn't be shown, a time alist to "H:M:S.ms" ;; Formats, disregarding min/hour if they shouldn't be shown, a time alist to "H:M:S.ms"
(defun format-time (time-alist) (defun format-time (time-alist)
@ -11,7 +13,7 @@
((hours (cdr (assoc 'hours time-alist))) ((hours (cdr (assoc 'hours time-alist)))
(minutes (cdr (assoc 'minutes time-alist))) (minutes (cdr (assoc 'minutes time-alist)))
(seconds (cdr (assoc 'seconds time-alist))) (seconds (cdr (assoc 'seconds time-alist)))
(centis (cdr (assoc 'cs time-alist)))) (centis (floor (/ (cdr (assoc 'millis time-alist)) 10))))
(concatenate 'string (concatenate 'string
(unless (zerop hours) (format nil "~2,'0d:" hours)) (unless (zerop hours) (format nil "~2,'0d:" hours))
(unless (and (zerop minutes) (zerop hours)) (format nil "~2,'0d:" minutes)) (unless (and (zerop minutes) (zerop hours)) (format nil "~2,'0d:" minutes))