Skip to content

Instantly share code, notes, and snippets.

@ivarref
Created August 23, 2019 14:26
Show Gist options
  • Save ivarref/02384ac213694c13d4f4b024602bd4b8 to your computer and use it in GitHub Desktop.
Save ivarref/02384ac213694c13d4f4b024602bd4b8 to your computer and use it in GitHub Desktop.
(ns ivarref.recurring-cup
(:require [tea-time.core :as tt]
[tea-time.virtual :as tv])
(:import (java.time ZonedDateTime ZoneId Instant DayOfWeek)
(java.time.format DateTimeFormatter)
(tea_time.core Task)))
;; Example of how to add scheduling of functions returning ZonedDateTime
;; and lazy sequences returning ZonedDateTime to aphyr/tea-time
(defn ^ZonedDateTime now-tz [tz]
(ZonedDateTime/ofInstant
(Instant/ofEpochSecond (tt/unix-time))
(ZoneId/of tz)))
(defn ^ZonedDateTime now-utc []
(now-tz "UTC"))
(defn daily
[{:keys [hour minute timezone]
:or {hour 0
minute 0
timezone "UTC"}}]
(fn
([]
(-> (now-tz timezone)
(.withNano 0)
(.withSecond 0)
(.withMinute minute)
(.withHour hour)
(#(if (or (.isEqual % (now-utc)) (.isAfter % (now-utc)))
%
(.plusDays % 1)))))
([prev-value]
(.plusDays prev-value 1))))
(defn hourly
[{:keys [minute timezone]
:or {minute 0
timezone "UTC"}}]
(fn
([]
(-> (now-tz timezone)
(.withNano 0)
(.withSecond 0)
(.withMinute minute)
(#(if (or (.isEqual % (now-utc)) (.isAfter % (now-utc)))
%
(.plusHours % 1)))))
([prev-value]
(.plusHours prev-value 1))))
(defn to-seq
([f] (to-seq (f) f))
([v f] (lazy-seq (cons v (to-seq (f v) f)))))
(defn zoned-date-time->linear-micros [^ZonedDateTime zdt]
(tt/unix-micros->linear-micros (tt/seconds->micros (.toEpochSecond zdt))))
(defrecord ZonedDateTimeFnTask [id f ^long t prev-time next-time-fn cancelled]
Task
(succ [this] (when-not @cancelled
(when-let [next-time (next-time-fn prev-time)]
(assoc this :t (zoned-date-time->linear-micros next-time)
:prev-time next-time))))
(run [this] (when-not @cancelled
(f)))
(cancel! [this]
(reset! cancelled true)))
(defn at-zdt-fn!
[zdt-fn f]
(let [first-time (zdt-fn)]
(tt/schedule! (ZonedDateTimeFnTask.
(tt/task-id)
f
(zoned-date-time->linear-micros first-time)
first-time
zdt-fn
(atom false)))))
(defn seq->fn! [s]
(let [state (atom s)]
(fn [& args]
(let [[head & tail] @state]
(reset! state tail)
head))))
(defn at-seq-fn!
[sq f]
(let [first-time (first sq)]
(tt/schedule! (ZonedDateTimeFnTask.
(tt/task-id)
f
(zoned-date-time->linear-micros first-time)
first-time
(seq->fn! (rest sq))
(atom false)))))
(defn now-println [& args]
(apply (partial println (.format (now-tz "Europe/Oslo") (DateTimeFormatter/ofPattern "E HH:mm")))
args))
(defn utc-println [& args]
(apply (partial println (.format (now-utc) (DateTimeFormatter/ofPattern "E HH:mm")))
args))
(comment
(->> (to-seq (daily {:hour 9 :minute 45 :timezone "Europe/Oslo"}))
(remove (comp #{DayOfWeek/SATURDAY DayOfWeek/SUNDAY} #(.getDayOfWeek %)))
(take 5)
(mapv #(.format % (DateTimeFormatter/ofPattern "E HH:mm")))))
(comment
(do
(tt/stop!)
(tv/reset-time!)
(tv/with-virtual-time!
(while (not= DayOfWeek/MONDAY (.getDayOfWeek (now-utc)))
(tv/advance! (+ (tt/unix-time) (* 24 3600))))
(at-seq-fn! (->> (to-seq (daily {:hour 9 :minute 45 :timezone "Europe/Oslo"}))
(remove (comp #{DayOfWeek/SATURDAY DayOfWeek/SUNDAY} #(.getDayOfWeek %))))
(fn [] (now-println "Get first cup of ☕")))
(tv/advance! (+ (tt/unix-time) (* 7 24 3600))))))
(comment
(do
(tt/stop!)
(tv/reset-time!)
(tv/with-virtual-time!
(tv/advance! (* 9 3600))
(at-zdt-fn! (hourly {:minute 45 :timezone "UTC"})
(fn [] (utc-println "Get another cup of ☕ \uD83D\uDE80\uD83D\uDE80\uD83D\uDE80")))
(tv/advance! (+ (tt/unix-time) (* 3 3600))))))
(comment
(do
(tt/stop!)
(tv/reset-time!)
(tv/with-virtual-time!
(at-zdt-fn! (daily {:hour 9 :minute 45 :timezone "Europe/Oslo"})
(fn [] (now-println "Get first cup of ☕ \uD83D\uDE80")))
(tv/advance! (* 7 24 3600)))))
;(println "it's now:" (.format (now-tz "Europe/Oslo") (DateTimeFormatter/ofPattern "HH:mm:ss.SSS")))
;((daily {:hour 2 :timezone "Europe/Oslo"})))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment