1    Introduction

1.1    Overview

std.lib.time is part of the standard foundation library set. This page collects the public API reference for the namespace.

2    Walkthrough

2.1    Reading the clock

std.lib.time provides thin wrappers around the system and high-resolution clocks. These are useful for timestamps, timeouts, and profiling.

system and high-resolution time are numbers

(system-ns) => number?
(system-ms) => number?
(time-ns)   => number?
(time-us)   => number?
(time-ms)   => number?

2.2    Formatting and parsing durations

format-ms turns a millisecond count into a human readable string, while parse-ms does the reverse. format-ns and parse-ns work with nanosecond precision.

format milliseconds for display

(format-ms 10000000)
=> "02h 46m 40s"

(format-ms 500)
=> "500ms"

(format-ms 65000)
=> "01m 05s"

parse duration strings to milliseconds

(parse-ms "1s")
=> 1000

(parse-ms "0.5h")
=> 1800000

(parse-ms "2m")
=> 120000

format and parse nanosecond values

(format-ns 1000000)
=> "1.000ms"

(parse-ns "2ns")
=> 2

(parse-ns "0.3s")
=> 300000000

2.3    Elapsed time and benchmarking

Use elapsed-ms and elapsed-ns to measure how much time has passed since a captured timestamp. The bench-ms and bench-ns macros run a body multiple times and report the average duration.

measure elapsed time

(elapsed-ms (- (time-ms) 10) true)
=> string?

(elapsed-ns (time-ns) true)
=> string?

benchmark a block

(bench-ms (Thread/sleep 10))
=> integer?

(bench-ns (Thread/sleep 1))
=> integer?

2.4    End-to-end: timing a small computation

Combine parsing, benchmarking, and formatting to describe how long an operation takes in friendly units.

parse a duration, sleep, then report elapsed time

(let [duration (parse-ms "100ms")
      start    (time-ms)]
  (Thread/sleep duration)
  (format-ms (elapsed-ms start)))
=> string?

3    API



*format* ^

NONE
(def ^:dynamic *format* nil)
link

*no-gc* ^

NONE
(def ^:dynamic *no-gc* false)
link

bench-form ^

[time-fn elapsed-fn opts body]

NONE
(defn- bench-form
  [time-fn elapsed-fn opts body]
  (let [[opts body] (cond (map? opts) [opts body]
                          :else [{} (cons opts body)])
        {:keys [format no-gc runs]
         :or {runs 1}} opts]
    `(binding [*format* ~format]
       (if-not (or ~no-gc *no-gc*)
         (System/gc))
       (let [start# (~time-fn)]
         (dotimes [_# ~runs]
           (do ~@body))
         (quot (~elapsed-fn start#) ~runs)))))
link

bench-ms ^

[opts & body]
Added 3.0

measures a block in milliseconds

v 3.0
(defmacro bench-ms
  ([opts & body]
   (bench-form `time-ms `elapsed-ms opts body)))
link
(bench-ms (Thread/sleep 10)) => integer?

bench-ns ^

[opts & body]
Added 3.0

measures a block in nanoseconds

v 3.0
(defmacro bench-ns
  ([opts & body]
   (bench-form `time-ns `elapsed-ns opts body)))
link
(bench-ns (Thread/sleep 1)) => integer?

elapsed-ms ^

[ms] [ms format]
Added 3.0

determines the time in ms that has elapsed

v 3.0
(defn elapsed-ms
  ([ms] (elapsed-ms ms *format*))
  ([ms format]
   (cond-> (- (time-ms) ms)
     format format-ms)))
link
(elapsed-ms (- (time-ms) 10) true) => string?

elapsed-ns ^

[ns] [ns format]
Added 3.0

determines the time in ns that has elapsed

v 3.0
(defn elapsed-ns
  ([ns] (elapsed-ns ns *format*))
  ([ns format]
   (cond-> (- (time-ns) ns)
     format (format-ns))))
link
(elapsed-ns (time-ns) true) ;; "35.42us" => string?

format-ms ^

[time]
Added 3.0

returns ms time is human readable format

v 3.0
(defn format-ms
  ([time]
   (let [millis  (mod time  1000)
         seconds (mod (quot time 1000) 60)
         mins    (mod (quot time (* 60 1000)) 60)
         hours   (mod (quot time (* 60 60 1000)) 24)
         days    (quot time (* 24 60 60 1000))
         level   (count (drop-while zero? [days hours mins seconds millis]))]
     (case level
       0 "0ms"
       1 (format "%03dms" millis)
       2 (format "%02ds %03dms" seconds millis)
       3 (format "%02dm %02ds" mins seconds)
       4 (format "%02dh %02dm %02ds" hours mins seconds)
       5 (format "%02dd %02dh %02dm" days mins seconds)))))
link
(format-ms 10000000) => "02h 46m 40s"

format-ns ^

[time] [time digits]
Added 3.0

returns ns time in seconds

v 3.0
(defn format-ns
  ([time]
   (format-ns time 4))
  ([time digits]
   (let [full   (str time)
         len    (count full)
         suffix (cond (<= 1 len 3)
                      "ns"
                      (<= 4 len 6)
                      "us"
                      (<= 7 len 9)
                      "ms"
                      (<= 10 len 12)
                      "s"
                      (<= 13 len 15)
                      "ks"
                      (<= 16 len 18)
                      "Ms"
                      (<= 19 len 21)
                      "Gs")
         decimal (inc (rem (dec len) 3))]
     (if (<= len digits)
       (str full "ns")
       (let [out (subs full 0 digits)]
         (str (subs out 0 decimal)
              "."
              (subs out decimal)
              suffix))))))
link
(format-ns 1000000) => "1.000ms"

parse-ms ^

[s]
Added 3.0

parses the string representation of time in ms

v 3.0
(defn parse-ms
  ([^String s]
   (let [len (count s)
         [s unit] (cond (.endsWith s "ms")
                        [(subs s 0 (- len 2)) 1]

                        :else
                        (let [unit (case (last s)
                                     d (* 24 60 60 1000)
                                     h (* 60 60 1000)
                                     m (* 60 1000)
                                     s 1000)]
                          [(subs s 0 (dec len)) unit]))
         v (Double/parseDouble s)]
     (long (* v unit)))))
link
(parse-ms "1s") => 1000 (parse-ms "0.5h") => 1800000

parse-ns ^

[s]
Added 3.0

parses the string repesentation of time in ns

v 3.0
(defn parse-ns
  ([^String s]
   (if (.endsWith s "s")
     (let [len  (count s)
           nchar (nth s (- len 2))
           [s unit] (cond (<= (int 0) (int nchar) (int 9))
                          [(subs s 0 (dec len)) 1000000000]

                          :else
                          (let [unit (case nchar
                                       n 1
                                       u 1000
                                       m 1000000
                                       k 1000000000000
                                       M 1000000000000000
                                       G 1000000000000000000)]
                            [(subs s 0 (- len 2)) unit]))
           v (Double/parseDouble s)]
       (long (* v unit))))))
link
(parse-ns "2ns") => 2 (parse-ns "0.3s") => 300000000

system-ms ^

[]
Added 3.0

returns the system milli time

v 3.0
(defn system-ms
  ([]
   (System/currentTimeMillis)))
link
(system-ms) => number?

system-ns ^

[]
Added 3.0

returns the system nano time

v 3.0
(defn system-ns
  ([]
   (System/nanoTime)))
link
(system-ns) ;; 8158606456270 => number?

time-ms ^

[]
Added 3.0

returns current time in milli seconds

v 3.0
(defn time-ms
  ([]
   (Clock/currentTimeMillis)))
link
(time-ms) ;; 1593922917603 => number?

time-ns ^

[]
Added 3.0

returns current time in nano seconds

v 3.0
(defn time-ns
  ([]
   (Clock/currentTimeNanos)))
link
(time-ns) ;; 1593922814991449423 => number?

time-us ^

[]
Added 3.0

returns current time in micro seconds

v 3.0
(defn time-us
  ([]
   (Clock/currentTimeMicros)))
link
(time-us) ;; 1593922882412533 => number?

4    std.lib.time: A Comprehensive Summary

The std.lib.time namespace provides a set of utility functions for working with time measurements in Clojure, offering high-resolution timing, human-readable formatting, and benchmarking capabilities. It leverages System/nanoTime and System/currentTimeMillis for precise measurements and includes functions for parsing time strings.

Key Features and Concepts:

  1. High-Resolution Time Measurement:n system-ns: Returns the system's current time in nanoseconds (from System/nanoTime).n system-ms: Returns the system's current time in milliseconds (from System/currentTimeMillis).n time-ns: Returns the current time in nanoseconds using hara.lib.foundation.Clock/currentTimeNanos for potentially more consistent or specialized timing.n time-us: Returns the current time in microseconds using hara.lib.foundation.Clock/currentTimeMicros.n time-ms: Returns the current time in milliseconds using hara.lib.foundation.Clock/currentTimeMillis).nn2. Time Formatting:n format-ms: Converts a duration in milliseconds into a human-readable string format (e.g., "02h 46m 40s").n format-ns: Converts a duration in nanoseconds into a human-readable string format, scaling to nanoseconds, microseconds, milliseconds, seconds, kiloseconds, megaseconds, or gigaseconds.nn3. Time Parsing:n parse-ms: Parses a string representation of time (e.g., "1s", "0.5h") into its equivalent duration in milliseconds.n parse-ns: Parses a string representation of time (e.g., "2ns", "0.3s") into its equivalent duration in nanoseconds.nn4. Elapsed Time Calculation:n elapsed-ms: Calculates the time elapsed in milliseconds since a given starting millisecond timestamp, with an option to format the output.n elapsed-ns: Calculates the time elapsed in nanoseconds since a given starting nanosecond timestamp, with an option to format the output.nn5. Benchmarking Macros:n bench-ns: A macro to measure the execution time of a code block in nanoseconds. It supports options for formatting, disabling garbage collection during measurement, and running the block multiple times.n * bench-ms: A macro to measure the execution time of a code block in milliseconds, with similar options to bench-ns.

Usage and Importance:

The std.lib.time module is essential for performance analysis, logging, and any application logic that requires precise timing or human-friendly time representations. Its benchmarking macros provide a convenient way to profile code execution, while the formatting and parsing functions facilitate user interaction and data processing involving time durations. This module contributes to the foundation-base project by offering robust and flexible tools for managing time-related aspects of applications.