>>1
Is using libraries meant for this sort of thing allowed? Some languages even include such functions in the standard lib, making this problem solvable with a one liner, but that would be pointless for a challenge.
(defun seconds-elapsed-from-unix-timestamp (unix-timestamp &optional (from-timestamp (local-time:timestamp-to-unix (local-time:now))))
"Calculates the difference in seconds, between 2 unix timestamps. If the FROM-TIMESTAMP parameter is not supplied, the current time is used." (let* ((elapsed (- from-timestamp unix-timestamp)) (from-future (< elapsed 0))) (values (abs elapsed) from-future)))
(defun decode-seconds (seconds)
"Decodes a seconds interval into seconds, minutes, hours, days, years." (multiple-value-bind (minutes seconds)(truncate seconds 60) (multiple-value-bind (hours minutes)(truncate minutes 60) (multiple-value-bind (days hours)(truncate hours 24) (multiple-value-bind (years days)(truncate days 365) (values seconds minutes hours days years))))))
(defmacro aif (test then &optional else)
"Anaphoric IF macro. Binds the result of evaluating TEST to the local variable IT."
`(let ((it ,test)) (declare (ignorable it)) (if it ,then ,else)))
(defun make-seconds-interval-string (seconds &optional (use-numerals t))
"Makes an english readable description of the SECONDS parameter.
USE-NUMERALS specifies wether the numerals should be written using decimals, or english words." (labels ((make-time-unit-string (value string) (let ((format-string (format nil"~~[~~:;~~:*~~~A ~A~~:p~~]" (if use-numerals "d" "r") string))) (format nil format-string value)))) (aif (remove "" (mapcar #'(lambda (value string) (make-time-unit-string value string)) (nreverse (multiple-value-list (decode-seconds seconds)))
'("year" "day" "hour" "minute" "second"))
:test #'equal) (format nil "~{~#[~;~a~;~a and ~a~:;~@{~a~#[~;, and ~:;, ~]~}~]~}" it))))
(defun format-seconds-elapsed-from-unix-timestamp-in-english (unix-timestamp &key (stream t) use-numerals reference-timestamp)
"Print an english readable description of the time that has passed since the given UNIX-TIMESTAMP to the stream STREAM (default *standard-output*).
USE-NUMERALS specifies wether the numerals should be written using decimals, or english words.
REFERENCE-TIMESTAMP specifies the timestamp from which time has supposedly passed or will pass. Ddefault is current time." (multiple-value-bind (elapsed-seconds from-future) (apply #'seconds-elapsed-from-unix-timestamp `(,unix-timestamp ,@(when reference-timestamp `(,reference-timestamp)))) (format stream "~@(~A~) ~A that timestamp." (aif (make-seconds-interval-string elapsed-seconds use-numerals) it "no time has") (if from-future "will pass to reach" "passed since"))))
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 123 :reference-timestamp 123)
No time has passed since that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 123 :reference-timestamp 124)
One second passed since that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 9999 :reference-timestamp 124)
Two hours, forty-four minutes, and thirty-five seconds will pass to reach that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 9999 :reference-timestamp 124 :use-numerals t)
2 hours, 44 minutes, and 35 seconds will pass to reach that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 9999 :reference-timestamp 124 :use-numerals t)
2 hours, 44 minutes, and 35 seconds will pass to reach that timestamp.
NIL
CL-USER> (+ (* 60 60 2)(* 60 60 24 9))
#xBF9A0
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english #xBF9A0 :reference-timestamp 0 :use-numerals t)
9 days and 2 hours will pass to reach that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 0 :reference-timestamp #xBF9A0)
Nine days and two hours passed since that timestamp.
NIL
CL-USER> (format-seconds-elapsed-from-unix-timestamp-in-english 0)
Forty years, one day, sixteen hours, forty-eight minutes, and twenty-four seconds passed since that timestamp.
NIL
|#
If theres ever a fire, the first thing you want to do is not get ran over by a crowed, pick up a char or desk or anything heavy and throw threw the window, this will give you a faster exit point and help remove smoke so people can breath.