Skip to content

Commit

Permalink
cljs tests passing
Browse files Browse the repository at this point in the history
  • Loading branch information
henryw374 committed Mar 4, 2024
1 parent ff033cb commit ce93335
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 513 deletions.
134 changes: 73 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,158 +126,170 @@ Depend on tempo via deps.edn:
(t/extend-cljs-protocols-to-instant)
```

### Construction and access/get
### Construction and access

#### Clocks
### Clocks

a Clock is required to be able to get the current time/date/zone etc

```clojure
;fixed in time and place
(t/clock-fixed (t/instant-now) "Europe/Paris")

; ambient place, ticking clock
; ticking clock in ambient place
(t/clock-system-default-zone)

; ticking clock in specified place
(t/clock-with-zone "Pacific/Honolulu")

; fixed in time and place
(t/clock-fixed (t/instant-parse "2020-02-02T00:00:00Z") "Europe/Paris")

; offset existing clock by specified millis
(t/clock-offset clock -5)
```

a clock is then passed as arg to all `now` functions, for example:

```clojure
(t/date-now clock)
```

#### Time zones
#### Time zones & Offsets

```clojure
(t/timezone-parse "Europe/London")

(t/timezone-now clock)
```

Where a timezone is accessed from an object, or passed into an object, only the string representation is used, referred to as `timezone_id`
Where a timezone is accessed from an object, or passed into an object, only the string representation is used, referred to as `timezone_id`. Call `str` on a timezone to get its id.

```clojure
(t/zdt->timezone_id zdt)
(t/zdt-from {:datetime datetime :timezone_id timezone})
(t/zdt-from {:datetime datetime :timezone_id timezone_id})
```

#### Temporals
### Temporals

```clojure

; Tempo construction and access is based on mnemonics
; naming of construction and access functions is based on mnemonics

; the first word in the function is the entity name of the subject of the operation

; for example, if I want to construct a date or access its parts the function will start t/date-,
; similarly for a zone-date-time, it will be t/zdt-*
(t/date-now)
(t/date-now clock)
(t/date-parse "2020-02-02") ;iso strings only
(t/date-from {:year 2020 :month 2 :day 2})
; the -from functions accept a map of components which is sufficient to build the entity
(t/datetime-from {:date (t/date-parse "2020-02-02") :time (t/time-now)})
(t/datetime-from {:date (t/date-parse "2020-02-02") :time (t/time-now clock)})
; or equivalently
(t/datetime-from {:year 2020 :month 2 :day 2 :time (t/time-now)})
(t/datetime-from {:year 2020 :month 2 :day 2 :time (t/time-now clock)})
; with -from, you can use smaller or larger components.
; larger ones take precedence. below, the :year is ignored, because the :date took precedence (being larger)
(t/datetime-from {:year 2021 :date (t/date-parse "2020-02-02") :time (t/time-now)})

; to get parts of an entity, start with the subject and add ->
(t/date->yearmonth (t/date-now))
(t/date->month (t/date-now))
(t/zdt->nanos (t/zdt-now))
(-> (t/instant-now) (t/instant->epochmillis))
(t/date->yearmonth (t/date-now clock))
(t/date->month (t/date-now clock))
(t/zdt->nanos (t/zdt-now clock))
(-> (t/instant-now clock) (t/instant->epochmillis))

```

#### Temporal-amounts

A temporal-amount is a quantity of time, e.g. hour, month, second.

Temporal-Amount entities are represented differently in java.time and Temporal, but with some overlap.

An `alpha` ns (groan!) exists which contains a few functions for working with temporal-amounts.
#### Manipulation

If not sufficient, use reader conditionals in your code to construct/manipulate as appropriate.
aka construction a new temporal from one of the same type

```clojure

(require '[com.widdindustries.tempo.duration-alpha :as d])

(d/duration-parse "PT0.001S")
;; move date forward 3 days
(t/>> (t/date-now clock) 3 t/days-property)

### Manipulation
;; set a particular field
(-> (t/yearmonth-now clock) (t/with 3030 t/years-property))

aka construction a new entity from one of the same type
; set fields smaller than days (ie hours, mins etc) to zero
(t/truncate x t/days-property)

#### Temporal-amounts
```

```clojure
#### Guardrails

(require '[com.widdindustries.tempo.duration-alpha :as d])
(t/+ (d/duration-parse "PT3H") (d/duration-parse "PT3S"))
Consider the following:

```clojure
(let [start (t/date-parse "2020-01-31")]
(-> start (t/>> 1 t/months-property)
(t/<< 1 t/months-property)))
```

#### Temporals
If you shift a date forward by an amount, then back by that amount then one might think the output would be equal to the input. In some cases that would happen, but not in the case shown above.

Here's a similar example:

```clojure
(let [start (t/date-parse "2020-02-29")]
(-> start
(t/with 2021 t/years-property)
(t/with 2020 t/years-property)))
```

(require '[com.widdindustries.tempo.duration-alpha :as d])
We increment the year, then decrement it, but the output is not the same as the input.

;; move date forward 3 days
(t/>> (t/date-now) (d/period-parse "P3D"))
Both java.time and Temporal work this way and in my experience it is a source of bugs. For this reason, shifting `>>/<<` and `with` do not work in Tempo if the property is years or months.

(-> (t/date-now) (t/with 3030 t/years-property))
As a safer alternative, I suggest getting the year-month from a temporal first, doing whatever with/shift operations you like then setting the remaining fields.

```
If you do not wish to have this guardrail, set `t/*block-non-commutative-operations*` to false

### Comparison

#### Temporal
```clojure

;only entities of the same type can be compared

(t/>= a b)


(t/max a b c)

; you must specify unit
; you must specify property
(t/until a b t/minutes-property)

```

### Predicates
#### Predicates

```clojure

(t/date? x)
```

### Guardrails
#### Temporal-amounts

Consider the following:
A temporal-amount is an entity representing a quantity of time, e.g. 3 hours and 5 seconds.

```clojure
(let [start (t/date-parse "2020-01-31")]
(-> start (t/>> 1 t/months-property)
(t/<< 1 t/months-property)))
```
Temporal-Amount entities are represented differently in java.time vs Temporal, but with some overlap.

If you shift a date forward by an amount, then back by that amount then you might think you'd end up with the date you started. Sometimes yes, in this case above, no.
An `alpha` ns (groan!) exists which contains a few functions for working with temporal-amounts.

Here's a similar example:
If not sufficient, use reader conditionals in your code to construct/manipulate as appropriate.

```clojure
(let [start (t/date-parse "2020-02-29")]
(-> start (t/with 2021 t/years-property)
(t/with 2020 t/years-property)))
```

We increment the year, then decrement it, but the output is not the same as the input.
(require '[com.widdindustries.tempo.duration-alpha :as d])

Both java.time and Temporal work this way and in my experience it is a source of bugs. For this reason, shifting `>>/<<` and `with` do not work in Tempo if the property is years or months.
(d/duration-parse "PT0.001S")

As a safer alternative, I suggest getting the year-month from a temporal first, doing whatever with/shift operations you like then setting the remaining fields.
```

If you do not wish to have this guardrail, set `t/*block-non-commutative-operations*` to false
In Tempo, some functions accept temporal-amounts as argument, but they are never returned from any function

It is preferred to use numbers and properties for example

```clojure
(t/>> a-date 1 t/days-property)
```

## Dev

Expand Down
2 changes: 1 addition & 1 deletion dev/com/widdindustries/gen/gen/accessors.clj
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@
~(when (and
(and (not= 'monthday subject) (not= 'month target-name))
(not (contains? #{'day-of-week 'date 'day-of-month 'instant 'datetime 'time 'timezone_id 'legacydate
'epochmilli}
'epochmilli 'year 'month}
target-name)))
(list 'is (list '= 'now-now (list 't/with 'now-now (list (symbol (str "t/" fn-name)) 'now-now) prop))))
))))))
Expand Down
27 changes: 16 additions & 11 deletions dev/com/widdindustries/gen/graph.clj
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@
(def epochmilli
{:tempo 'epochmilli
:return 'int?
:cljay {:accessor 'toEpochMilli}})
:cljay {:accessor 'toEpochMilli}
:cljs {:xform-fn '(-> (.-epochMilliseconds))}})

(def epochnano
{:ignore-accessor true ; its not in java
Expand Down Expand Up @@ -87,7 +88,7 @@
(def monthday
{:tempo 'monthday
:ignore-accessor true
:needed-to-go-up {'year {}}
:needed-to-go-up {'year {}}
:cljay {:no-getter true
:fn-args ['month 'day-of-month]
:fn (fn [month day]
Expand All @@ -114,7 +115,7 @@
{:tempo 'legacydate
:cljay {:xform-fn '(-> (.toEpochMilli) (java.util.Date.))}
:cljs {
:xform-fn '(-> (.-epochMilliseconds) (Date.))
:xform-fn '(-> (.-epochMilliseconds) (js/Date.))
}} {}}}
{:tempo 'zdt
;todo - https://tc39.es/proposal-temporal/docs/zoneddatetime.html#startOfDay
Expand All @@ -136,10 +137,14 @@
:return 'int?} {}
month {}}}}}
{:parts
{monthday {:parts {month {}
{monthday {:parts {{:tempo 'month
:return 'int?
;get month not gener
:cljay {:accessor 'getMonthValue}
:cljs {:xform-fn '(-> (.-monthCode) (subs 1 3) js/parseInt)}} {}
{:tempo 'day-of-month
:return 'int?
:cljs {:accessor '-day}} {}}}}}
:cljs {:accessor '-day}} {}}}}}
{:parts
{{:tempo 'year
:return 'int?} {}
Expand All @@ -151,20 +156,20 @@
{day-of-week {}}}]
}
{:tempo 'time} {:parts {{:tempo 'hour
:return 'int?} {}
:return 'int?} {}
{:tempo 'minute
:return 'int?} {}
:return 'int?} {}
{:tempo 'second
:return 'int?} {}
:return 'int?} {}
{:tempo 'millisecond
:return 'int?
:cljay {:xform-fn '(-> -millisecond)}} {}
:cljay {:xform-fn '(-> -millisecond)}} {}
{:tempo 'microsecond
:return 'int?
:cljay {:xform-fn '(-> -microsecond)}} {}
:cljay {:xform-fn '(-> -microsecond)}} {}
{:tempo 'nanosecond
:return 'int?
:cljay {:xform-fn '(-> -nanosecond)}} {}}}}}}}]}})
:cljay {:xform-fn '(-> -nanosecond)}} {}}}}}}}]}})

(def with-paths (paths graph))

Expand Down
2 changes: 1 addition & 1 deletion dev/dev.clj
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
(capt/capt
'(do
(require '[com.widdindustries.gen.gen.tempo] :reload)
(require '[com.widdindustries.gen.gen.accessors] :reload)
(require '[com.widdindustries.gen.gen.accessors] :reload-all)
(gen/gen-after)))

(capt/exec)
Expand Down
2 changes: 1 addition & 1 deletion gen_in/constructors.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
(ZonedDateTime/ofInstant instant (timezone-parse zone))
(ZonedDateTime/of ^LocalDateTime ldt ^ZoneId (timezone-parse zone)))
:cljs (if instant
(.toZonedDateTimeISO ^js instant (ZoneId/of zone))
(.toZonedDateTimeISO ^js instant zone)
(.toZonedDateTime ^js ldt zone)))))

(defn instant-from [thing]
Expand Down
Loading

0 comments on commit ce93335

Please sign in to comment.