Ep 017: Data, at Your Service

Play Episode

Nate finds it easier to get a broad view without a microscope.

Related episodes:

Clojure in this episode:

Code sample from this episode:

(ns time.week-03
    [clojure.java.io :as io]
    [clojure.string :as string]
    [java-time :as jt]))

; Functions for parsing out the time format: Fri Feb 08 2019 11:30-13:45

(def timestamp-re #"(\w+\s\w+\s\d+\s\d+)\s+(\d{2}:\d{2})-(\d{2}:\d{2})")

(defn localize [dt tm]
  (jt/zoned-date-time dt tm (jt/zone-id)))

(defn parse-time [time-str]
  (jt/local-time "HH:mm" time-str))

(defn parse-date [date-str]
  (jt/local-date "EEE MMM dd yyyy" date-str))

(defn adjust-for-midnight
  [start end]
  (if (jt/before? end start)
    (jt/plus end (jt/days 1))

(defn parse
  (when-let [[whole dt start end] (re-matches timestamp-re line)]
    (let [date (parse-date dt)
          start (localize date (parse-time start))
          end (adjust-for-midnight start (localize date (parse-time end)))]
      {:date date
       :start start
       :end end
       :minutes (jt/time-between start end :minutes)})))

; How many minutes did I work on each day?

(defn daily-total-minutes
  (->> times
       (group-by :date)
       (map (fn [[date entries]] (vector date (reduce + (map :minutes entries)))))
       (into {})))

; How many minutes total did I work on Sundays?

(defn on-sunday?
  [{:keys [date]}]
  (= (jt/day-of-week date) (jt/day-of-week :sunday)))

(defn sunday-minutes
  (->> times
       (filter on-sunday?)
       (map :minutes)
       (reduce +)))

; Functions for turning the time log into a sequence of time entries

(defn lines
  (->> (slurp filename)

(defn times
  (->> lines
       (map parse)
       (filter some?)))

; Process a time log with the desired summary calculation

(defn summarize
  [filename calc]
  (->> (lines filename)

  (summarize "time-log.txt" daily-total-minutes)
  (summarize "time-log.txt" sunday-minutes)