    :eras ChronoUnit/ERAS
    :forever ChronoUnit/FOREVER})
 
+(def reverse-unit-map (into {} (map vec (map reverse unit-map))))
+
+(defn units [x]
+  (into {}
+        (for [tu (.getUnits x)
+              :let [k (reverse-unit-map tu)]
+              :when k]
+          [k (.get x tu)])))
+
+;; Durations
+
+(defprotocol IDuration
+  (nanos [_] "Return the given quantity in nanoseconds.")
+  (micros [_] "Return the given quantity in microseconds.")
+  (millis [_] "Return the given quantity in milliseconds.")
+  (seconds [_] "Return the given quantity in seconds.")
+  (minutes [_] "Return the given quantity in minutes.")
+  (hours [_] "Return the given quantity in hours.")
+  (days [_] "Return the given quantity in days."))
+
+(extend-protocol IDuration
+  Number
+  (nanos [n] (Duration/ofNanos n))
+  (micros [n] (Duration/ofNanos (* n 1000)))
+  (millis [n] (Duration/ofMillis n))
+  (seconds [n] (Duration/ofSeconds n))
+  (minutes [n] (Duration/ofMinutes n))
+  (hours [n] (Duration/ofHours n))
+  (days [n] (Duration/ofDays n))
+
+  Duration
+  (nanos [d] (.toNanos d))
+  (micros [d] (Long/divideUnsigned (nanos d) 1000))
+  (millis [d] (.toMillis d))
+  (seconds [d] (.getSeconds d))
+  (minutes [d] (.toMinutes d))
+  (hours [d] (.toHours d))
+  (days [d] (.toDays d)))
+
 (defn duration [n u]
   (let [unit (unit-map u)]
     (assert unit (str "Not a unit: " u))

    :months (Period/ofMonths n)
    :years (Period/ofYears n)))

;; Units

(def reverse-unit-map (into {} (map vec (map reverse unit-map))))

(defn units [x]
  (into {}
        (for [tu (.getUnits x)
              :let [k (reverse-unit-map tu)]
              :when k]
          [k (.get x tu)])))

;; Between

(defprotocol ITimeBetween
  (between [t1 t2] "Return the most appropriate type of value that
  represents the gap between two times"))

(extend-protocol ITimeBetween
  Instant
  (between [inst _] (throw (ex-info "TODO" {}))))

(defprotocol ITimeComparison
  (< [x y] "Is x before y?")
  (<= [x y] "Is x before or at the same time as y?")
  (> [x y] "Is x after y?")
  (>= [x y] "Is x after or at the same time as y?"))

(extend-protocol ITimeComparison
  Instant
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  LocalDateTime
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  LocalTime
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  LocalDate
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  OffsetDateTime
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  ZonedDateTime
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  YearMonth
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y)))

  Year
  (< [x y] (.isBefore x y))
  (<= [x y] (not (.isAfter x y)))
  (> [x y] (.isAfter x y))
  (>= [x y] (not (.isBefore x y))))

(defprotocol ITimeRangeable
  (range [_] [_ _] [_ _ _] "Returns a lazy seq of times from start (inclusive) to end (exclusive, nil means forever), by step, where start defaults to 0, step to 1, and end to infinity."))

(defprotocol IDivisible
  (/ [_ _] "Divide time"))

(extend-protocol IDivisible
  String
  (/ [s d] (/ (parse s) d)))

(defprotocol ITimeArithmetic
  (+ [_ _] "Add time")
  (- [_ _] "Subtract time"))

    ([from to step] (cond->> (iterate #(.plus % step) from)
                      to (take-while #(< % to))))))

(defprotocol IDivisible
  (/ [_ _] "Divide time"))

(extend-protocol IDivisible
  String
  (/ [s d] (/ (parse s) d)))

(defprotocol IDivisibleDuration
  (divide-duration [divisor duration] "Divide a duration"))

(extend-protocol IDivisibleDuration
  Long
  (divide-duration [n duration] (.dividedBy duration n))
  Duration
