diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ddcec46 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,106 @@ +name: Build + +on: + push: + branches: + - master + pull_request: + schedule: + # monthly + - cron: "0 0 1 * *" + +env: + #bump to clear caches + ACTION_CACHE_VERSION: 'v2' + LEIN_VERSION: '2.11.2' + +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: | + ~/.m2/repository + key: ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj', '**/bb.edn') }} + restore-keys: | + ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven- + - name: Prepare java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 11 + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@13.4 + with: + lein: ${{ env.LEIN_VERSION }} + - name: Warm deps cache + run: lein all deps + lint: + needs: setup + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj', '**/bb.edn') }} + restore-keys: | + ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven- + - name: Prepare java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 11 + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@13.4 + with: + lein: ${{ env.LEIN_VERSION }} + - name: Run Eastwood + run: lein eastwood + test-jvm: + needs: setup + strategy: + matrix: + java: ['8', '11', '17', '21', '24'] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj', '**/bb.edn') }} + restore-keys: | + ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven- + - name: Prepare java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@13.4 + with: + lein: ${{ env.LEIN_VERSION }} + - name: Run JVM tests + run: lein test-all +# test-bb: +# needs: setup +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# - name: Prepare java +# uses: actions/setup-java@v4 +# with: +# distribution: 'temurin' +# java-version: 17 +# - name: Install clojure tools +# uses: DeLaGuardo/setup-clojure@13.4 +# with: +# bb: latest +# - name: Run Babashka tests +# run: ./bin/bb-test-runner.sh diff --git a/.gitignore b/.gitignore index 01ebc2a..4c87c92 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ pom.xml.asc *.class .lein-* /.nrepl-port +.eastwood +/bb # deps.edn .cpcache/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f64878f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: clojure -lein: lein -script: lein test-all -jdk: - - oraclejdk11 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e17074..e8d634d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,80 @@ # Changelog -## 0.3.4 +## NEXT + +## 1.4.3 + +- [#114](https://github.com/dm3/clojure.java-time/pull/114): fix doc typo ([@metayan](https://github.com/metayan)) +- [#111](https://github.com/dm3/clojure.java-time/issues/111): docstrings of java-time.api contain literal \n ([@devurandom](https://github.com/devurandom) + +## 1.4.2 + +- [#105](https://github.com/dm3/clojure.java-time/issues/105): fix `not-{before,after}?` on unconverted values + - a consequence of fixing [#104](https://github.com/dm3/clojure.java-time/issues/104) +- add `java-time.api/=` for equality of times (with conversions) +- add support to intermix unconverted values in comparison operations after first argument + - supported by `{before,after}?`, `not-{before,after}?`, `j/=`, and aliases of those ops + - examples: + - `(j/< (j/day-of-week :thursday) :saturday :sunday)` + - `(j/<= (j/day-of-week :thursday) :thursday (j/day-of-week :saturday) :sunday)` + - `(j/= (j/day-of-week :thursday) :thursday (j/day-of-week :thursday) :thursday)` + +## 1.4.1 + +- [#104](https://github.com/dm3/clojure.java-time/issues/104): fix transivitity of `not-{before,after}?` when called with intervals + +## 1.4.0 + +- [#98](https://github.com/dm3/clojure.java-time/issues/98): fix `not-before?` and `not-after?` with one or more than two arguments +- new aliases + - `java-time.api/+` aliases `java-time.api/plus` + - `java-time.api/-` aliases `java-time.api/minus` + - `java-time.api/neg?` aliases `java-time.api/negative?` + - `java-time.api/<` aliases `java-time.api/before?` + - `java-time.api/>` aliases `java-time.api/after?` + - `java-time.api/<=` aliases `java-time.api/not-after?` + - `java-time.api/>=` aliases `java-time.api/not-before?` + +## 1.3.0 + +- remove `:redef` on protocol methods, they are never direct-linked: https://ask.clojure.org/index.php/10967/are-protocol-methods-guaranteed-to-not-be-directly-linked?show=10990#a10990 +- [#100](https://github.com/dm3/clojure.java-time/issues/100): respect `*clock*` when only providing a zone id in constructors + +## 1.2.0 + +- [#95](https://github.com/dm3/clojure.java-time/issues/95) work around [CLJ-1796](https://clojure.atlassian.net/browse/CLJ-1796) + +## 1.1.0 + +Due to [#91](https://github.com/dm3/clojure.java-time/issues/91), the main `java-time` +namespace has been deprecated. A new namespace `java-time.api` has been created + +Note that this change is entirely optional---`java-time` and `java-time.api` will continue to be in sync and may coexist. + +See [the docstring for `java-time`](https://dm3.github.io/clojure.java-time/java-time.html) for more details. + +## 1.0.0 + +Released 2022-11-24. + +### New Features + +* Previously, Intervals were only allowed to the left of Instants in {before,after}?. Now they can be freely intermixed. ### Fixed * #78(liquidz): Add missing chrono fields (v0.3.3 has breaking changes) * #81(terop): Remove clj-tuple - no advantages over Clojure vector anymore +* #52: Fix before/after on Intervals +* #83(imrekoszo): Exclude clojure.core/abs + +### Enhancements +* add docstrings to all `java-time` fns +* support clj-kondo in `java-time` ns by adding `:arglists` to all vars + +### Internal +* Deprecate `java-time.util/get-static-fields-of-type` +* Remove `java-time.potemkin.namespaces` ## 0.3.3 diff --git a/README.md b/README.md index 8739a46..30fc33f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ # Clojure.Java-Time -[![Build Status](https://travis-ci.org/dm3/clojure.java-time.png?branch=master)](https://travis-ci.org/dm3/clojure.java-time) +[![Clojars Project](https://img.shields.io/clojars/v/clojure.java-time.svg)](https://clojars.org/clojure.java-time) A Clojure wrapper for Java 8 Date-Time API. +> Note: This library has no relation to Clojure's (or Java's) core team. +> It's naming is legacy and preserved for backwards compatibility reasons. + ## Rationale Main goals: @@ -38,7 +41,7 @@ is purely on the merits of a broader feature set. ## Documentation -* [API](http://dm3.github.io/clojure.java-time/) +* [API](https://dm3.github.io/clojure.java-time/) * [![cljdoc badge](https://cljdoc.org/badge/clojure.java-time/clojure.java-time)](https://cljdoc.org/d/clojure.java-time/clojure.java-time/CURRENT) ## What's different in Java Time API? @@ -50,100 +53,109 @@ complicated than it has to be. Also, a few concepts have faulty designs which lead to hard to fix bugs and misuse. You can see the birds-eye view of changes and some of the rationale on the author's (Stephen Colebourne) blog: -* [what's wrong with Joda-Time](http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html), -* [when you should use Java-Time](http://blog.joda.org/2014/07/threeten-backport-vs-joda-time.html) -* [what's different in Java-Time](http://blog.joda.org/2014/11/converting-from-joda-time-to-javatime.html). +* [what's wrong with Joda-Time](https://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html), +* [when you should use Java-Time](https://blog.joda.org/2014/07/threeten-backport-vs-joda-time.html) +* [what's different in Java-Time](https://blog.joda.org/2014/11/converting-from-joda-time-to-javatime.html). You can also take a look at a [comprehensive comparison](http://time4j.net/tutorial/appendix.html) by the [Time4J](http://time4j.net/) authors. ## Usage -Add the following dependency to your `deps.edn` +Add the following dependency to your `deps.edn`: ```clj -clojure.java-time/clojure.java-time {:mvn/version "0.3.3"} +clojure.java-time/clojure.java-time {:mvn/version "1.4.3"} ``` or to your `project.clj` or `build.boot`: - ```clj -[clojure.java-time "0.3.3"] +[clojure.java-time "1.4.3"] ``` -The [API](https://dm3.github.io/clojure.java-time/) of the Clojure.Java-Time -consists of one namespace, namely `java-time`. For the purposes of this guide, -we will `use` the main namespace: +The [API](https://dm3.github.io/clojure.java-time) of the Clojure.Java-Time +consists of one namespace, namely `java-time.api`. For the purposes of this guide, +we will `require` the main namespace: ```clj -(refer-clojure :exclude [range iterate format max min]) -(use 'java-time) +(require '[java-time.api :as jt] + ;; for REPL experimentation + 'java-time.repl) ``` ### Concept run-through -Java Time API may seem daunting. Instead of a single `java.util.Date` you have +The Java Time API may seem daunting. Instead of a single `java.util.Date` you have a `ZonedDateTime`, `OffsetDateTime`, `LocalDateTime`, `Instant`, and other types. You would be well served by reading the official documentation for the [Java Time API](https://docs.oracle.com/javase/tutorial/datetime/iso/index.html), but we'll also do a quick run-through here. -#### Local Dates +#### Local Dates and/or Times `LocalDate`, `LocalTime` and `LocalDateTime` are used to represent a date, time -and date-time respectively without an offset or a timezone. The local time entities +and date-time respectively without an offset or a time zone. The local time entities are used to represent human-based dates/times. They are a good fit for representing the time of various events: * `LocalDate` - birthday, holiday + * see [`jt/local-date`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-date) * `LocalTime` - bus schedule, opening time of a shop + * see [`jt/local-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-time) * `LocalDateTime` - start of a competition + * see [`jt/local-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-date-time) -A local date/time can be created as you'd expect: +Example usage: ```clj -(local-date 2015 10) -=> # +(jt/local-date 2015 10) +;=> # -(local-time 10) -=> # +(jt/local-time 10) +;=> # -(local-date-time 2015 10) -=> # +(jt/local-date-time 2015 10) +;=> # ``` #### Zoned Dates -There are two types which deal with zones: `OffsetDateTime` and -`ZonedDateTime`. They do pretty much what you would expect from their name. +There are two types which deal with zones: +* `OffsetDateTime` + * see [`jt/offset-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-offset-date-time) +* `ZonedDateTime` + * see [`jt/zoned-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-zoned-date-time) + +They do pretty much what you would expect from their name. You can think of the `Offset` time as a more concrete version of the `Zoned` -time. For example, the same timezone can have different offsets throughout the +time. For example, the same time zone can have different offsets throughout the year due to DST or governmental regulations. ```clj -(offset-time 10) -=> # +(jt/offset-time 10) +;=> # -(offset-date-time 2015 10) -=> # +(jt/offset-date-time 2015 10) +;=> # -(zoned-date-time 2015 10) -=> # +(jt/zoned-date-time 2015 10) +;=> # ``` Offset/Zone times only take the offset/zone as the last arguments for the maximum arity constructor. You can influence the zone/offset by using the -`with-zone` or `with-offset` functions, like so: +[`jt/with-zone`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-with-zone) +or [`jt/with-offset`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-with-offset) functions, like so: ```clj -(with-zone (zoned-date-time 2015 10) "UTC") -=> # +(jt/with-zone (jt/zoned-date-time 2015 10) "UTC") +;=> # -(with-zone-same-instant (zoned-date-time 2015 10) "UTC") -=> # +(jt/with-zone-same-instant (jt/zoned-date-time 2015 10) "UTC") +;=> # -(with-clock (system-clock "UTC") - (zoned-date-time 2015 10)) -=> # +(jt/with-clock (jt/system-clock "UTC") + (jt/zoned-date-time 2015 10)) +;=> # ``` #### Instant @@ -154,11 +166,11 @@ milliseconds since epoch (`1970-01-01T00:00:00Z`). An instant is directly analogous to `java.util.Date`: ```clj -user=> (instant) -# +(jt/instant) +;=> # -user=> (java.util.Date.) -#inst "2015-09-26T05:25:50.118-00:00" +(java.util.Date.) +;=> #inst "2015-09-26T05:25:50.118-00:00" ``` Every other date entity can be converted to an instant (local ones will require @@ -181,13 +193,13 @@ constructors you are going to use up by calling them beforehand, e.g.: ```clj (defn warm-up [] - (zoned-date-time 2015 1 1) - (zoned-date-time 2015 1) - (zoned-date-time 2015)) + (jt/zoned-date-time 2015 1 1) + (jt/zoned-date-time 2015 1) + (jt/zoned-date-time 2015)) ``` The "constructor" here refers to an arity of a function together with its type -signature. For example, a `(zoned-date-time 2015)` and `(zoned-date-time (system-clock))` +signature. For example, a `(jt/zoned-date-time 2015)` and `(jt/zoned-date-time (jt/system-clock))` are different constructors. ### An appetizer @@ -197,156 +209,164 @@ First, let's do a quick run through common use cases. What is the current date? ```clj -(def now (local-date)) -=> #object[java.time.LocalDate "2015-09-27"] +(def now (jt/local-date)) +;=> #object[java.time.LocalDate "2015-09-27"] ``` What's the next day? ```clj -(plus now (days 1)) -=> #object[java.time.LocalDate "2015-09-28"] +(jt/plus now (jt/days 1)) +;=> #object[java.time.LocalDate "2015-09-28"] ``` The previous day? ```clj -(minus now (days 1)) -=> #object[java.time.LocalDate "2015-09-26"] +(jt/minus now (jt/days 1)) +;=> #object[java.time.LocalDate "2015-09-26"] ``` Three days starting at `now`? ```clj -(take 3 (iterate plus now (days 1))) ;; note `java-time/iterate` -=> (#object[java.time.LocalDate "2015-09-27"] - #object[java.time.LocalDate "2015-09-28"] - #object[java.time.LocalDate "2015-09-29"]) +(take 3 (jt/iterate jt/plus now (jt/days 1))) +;=> (#object[java.time.LocalDate "2015-09-27"] +; #object[java.time.LocalDate "2015-09-28"] +; #object[java.time.LocalDate "2015-09-29"]) ``` When is the first Monday in month? ```clj -(adjust now :first-in-month :monday) -=> #object[java.time.LocalDate "2015-09-07"] +(jt/adjust now :first-in-month :monday) +;=> #object[java.time.LocalDate "2015-09-07"] ``` Date with some of its fields truncated: ```clj -(truncate-to (local-date-time 2015 9 28 10 15) :days) -=> #object[java.time.LocalDateTime "2015-09-28T00:00"] +(jt/truncate-to (jt/local-date-time 2015 9 28 10 15) :days) +;=> #object[java.time.LocalDateTime "2015-09-28T00:00"] ``` Date-time adjusted to the given hour: ```clj -(adjust (local-date-time 2015 9 28 10 15) (local-time 6)) -=> #object[java.time.LocalDateTime "2015-09-28T06:00"] +(jt/adjust (jt/local-date-time 2015 9 28 10 15) (jt/local-time 6)) +;=> #object[java.time.LocalDateTime "2015-09-28T06:00"] ``` The latest of the given dates? ```clj -(max (local-date 2015 9 20) (local-date 2015 9 28) (local-date 2015 9 1)) -=> #object[java.time.LocalDate "2015-09-28"] +(jt/max (jt/local-date 2015 9 20) (jt/local-date 2015 9 28) (jt/local-date 2015 9 1)) +;=> #object[java.time.LocalDate "2015-09-28"] ``` The shortest of the given durations? ```clj -(min (duration 10 :seconds) (duration 5 :hours) (duration 3000 :millis)) -=> #object[java.time.Duration "PT3S"] +(jt/min (jt/duration 10 :seconds) (jt/duration 5 :hours) (jt/duration 3000 :millis)) +;=> #object[java.time.Duration "PT3S"] ``` Get the year field out of the date: ```clj -(as (local-date 2015 9 28) :year) -=> 2015 +(jt/as (jt/local-date 2015 9 28) :year) +;=> 2015 ``` Get multiple fields: ```clj -(as (local-date 2015 9 28) :year :month-of-year :day-of-month) -=> (2015 9 28) +(jt/as (jt/local-date 2015 9 28) :year :month-of-year :day-of-month) +;=> (2015 9 28) ``` Get the duration in a different unit: ```clj -java-time> (plus (hours 3) (minutes 2)) -#object[java.time.Duration "PT3H2M"] -java-time> (as *1 :minutes) -182 +(jt/plus (jt/hours 3) (jt/minutes 2)) +;=> #object[java.time.Duration "PT3H2M"] + +(jt/as *1 :minutes) +;=> 182 ``` Format a date: ```clj -(format "MM/dd" (zoned-date-time 2015 9 28)) -=> "09/28" +(jt/format "MM/dd" (jt/zoned-date-time 2015 9 28)) +;=> "09/28" ``` Parse a date: ```clj -(local-date "MM/yyyy/dd" "09/2015/28") -=> #object[java.time.LocalDate "2015-09-28"] +(jt/local-date "MM/yyyy/dd" "09/2015/28") +;=> #object[java.time.LocalDate "2015-09-28"] ``` Zoned date-times and offset date-times/times always take the zone/offset as the last argument. Offsets can be specified as float values: ```clj -(zone-offset +1.5) -=> # +(jt/zone-offset +1.5) +;=> # -(zone-offset -1.5) -=> # +(jt/zone-offset -1.5) +;=> # ``` Compare dates: ```clj -(before? (year 2020) (year 2021)) -=> true +(jt/before? (jt/year 2020) (jt/year 2021)) +;=> true -(after? (year 2021) (year 2021)) -=> false +(jt/after? (jt/year 2021) (jt/year 2021)) +;=> false -(let [expiration-date (year 2010) - purchase-date (year 2010)] - (not-before? expiration-date purchase-date)) -=> true +(let [expiration-date (jt/year 2010) + purchase-date (jt/year 2010)] + (jt/not-before? expiration-date purchase-date)) +;=> true -(let [start-date (year 2011) - cutoff-date (year 2010)] - (not-after? start-date cutoff-date)) -=> false +(let [start-date (jt/year 2011) + cutoff-date (jt/year 2010)] + (jt/not-after? start-date cutoff-date)) +;=> false ``` #### Conversions Time entities can be converted to other time entities if the target contains -less information, e.g. (assuming we're in UTC timezone): +less information, e.g. (assuming we're in UTC time zone): ```clj -(zoned-date-time (offset-date-time 2015 9 28 1)) -=> #object[java.time.ZonedDateTime "2015-09-28T01:00Z"] +(jt/zoned-date-time (jt/offset-date-time 2015 9 28 1)) +;=> #object[java.time.ZonedDateTime "2015-09-28T01:00Z"] -(instant (offset-date-time 2015 9 28 1)) -=> #object[java.time.Instant "2015-09-28T01:00:00Z"] +(jt/instant (jt/offset-date-time 2015 9 28 1)) +;=> #object[java.time.Instant "2015-09-28T01:00:00Z"] -(offset-time (offset-date-time 2015 9 28 1)) -=> #object[java.time.OffsetTime "01:00Z"] +(jt/offset-time (jt/offset-date-time 2015 9 28 1)) +;=> #object[java.time.OffsetTime "01:00Z"] -(local-date-time (offset-date-time 2015 9 28 1)) -=> #object[java.time.LocalDateTime "2015-09-28T01:00"] +(jt/local-date-time (jt/offset-date-time 2015 9 28 1)) +;=> #object[java.time.LocalDateTime "2015-09-28T01:00"] -(local-time (offset-time 1)) -=> #object[java.time.LocalTime 0x3a3cd6d5 "01:00"] +(jt/local-time (jt/offset-time 1)) +;=> #object[java.time.LocalTime 0x3a3cd6d5 "01:00"] +``` + +Converting an Instant to ZonedDateTime requires a time zone: + +```clojure +(jt/zoned-date-time (jt/instant 100) "UTC") +;=> #object[java.time.ZonedDateTime 0x291777c0 "1970-01-01T00:00:00.100Z[UTC]"] ``` #### Legacy Date-Time Types @@ -355,53 +375,53 @@ Any date which can be converted to an instant, can also be converted to a `java.util.Date`: ```clojure -(java-date (zoned-date-time 2015 9 28)) -=> #inst "2015-09-27T22:00:00.000-00:00" +(jt/java-date (jt/zoned-date-time 2015 9 28)) +;=> #inst "2015-09-27T22:00:00.000-00:00" -(java-date 50000) -=> #inst "1970-01-01T00:00:50.000-00:00" +(jt/java-date 50000) +;=> #inst "1970-01-01T00:00:50.000-00:00" ``` An instance of `java.util.Date` serves the same purpose as the new `java.time.Instant`. It's a machine timestamp which isn't aware of the -timezone. Please, do not get confused by the way it is printed by the Clojure -printer - the UTC timezone is applied during formatting. +time zone. Please, do not get confused by the way it is printed by the Clojure +printer - the UTC time zone is applied during formatting. -Sometimes you'll have to work with the legacy `java.sql.Date/Time/Timestamp` +Sometimes you'll have to work with the legacy `java.sql.{Date,Time,Timestamp}` types. The correspondence between the legacy types and the new Date-Time entities is as follows: - * `java.time.LocalDate` - `java.sql.Date` - * `java.time.LocalDateTime` - `java.sql.Timestamp` - * `java.time.LocalTime` - `java.sql.Time` + * `java.sql.Date` <-> `java.time.LocalDate` + * `java.sql.Timestamp` <-> `java.time.LocalDateTime` + * `java.sql.Time` <-> `java.time.LocalTime` ```clojure -(sql-date 2015 9 28) -=> #inst "2015-09-27T22:00:00.000-00:00" +(jt/sql-date 2015 9 28) +;=> #inst "2015-09-27T22:00:00.000-00:00" -(sql-timestamp 2015 9 28 10 20 30 4000000) -=> #inst "2015-09-28T09:20:30.004-00:00" +(jt/sql-timestamp 2015 9 28 10 20 30 4000000) +;=> #inst "2015-09-28T09:20:30.004-00:00" -(sql-time 10 20 30) -=> #inst "1970-01-01T09:20:30.000-00:00" +(jt/sql-time 10 20 30) +;=> #inst "1970-01-01T09:20:30.000-00:00" ``` The results of the above calls get printed as `#inst` because all of the -`java.sql.Date/Time/Timestamp` are subtypes of `java.util.Date`. +`java.sql.{Date,Time,Timestamp}` are subtypes of `java.util.Date`. Coincidentally, this makes it impossible to plug the `java.sql.*` types into the Clojure.Java-Time conversion graph. Conversions to the legacy types also go the other way around: ```clojure -(j/local-date (j/sql-date 2015 9 28)) -#object[java.time.LocalDate "2015-09-28"] +(jt/local-date (jt/sql-date 2015 9 28)) +;=> #object[java.time.LocalDate "2015-09-28"] -(j/local-date-time (j/sql-timestamp 2015 9 28 10 20 30 4000000)) -#object[java.time.LocalDateTime "2015-09-28T10:20:30.004"] +(jt/local-date-time (jt/sql-timestamp 2015 9 28 10 20 30 4000000)) +;=> #object[java.time.LocalDateTime "2015-09-28T10:20:30.004"] -(j/local-time (j/sql-time 10 20 30)) -#object[java.time.LocalTime "10:20:30"] +(jt/local-time (jt/sql-time 10 20 30)) +;=> #object[java.time.LocalTime "10:20:30"] ``` #### Three-Ten Extra @@ -414,34 +434,34 @@ An interval can be constructed from two entities that can be converted to instants: ```clojure -(interval (offset-date-time 2015 1 1) (zoned-date-time 2016 1 1)) -=> # +(jt/interval (jt/offset-date-time 2015 1 1) (jt/zoned-date-time 2016 1 1)) +;=> # -(move-start-by *1 (duration 5 :days)) -=> # +(jt/move-start-by *1 (jt/duration 5 :days)) +;=> # -(move-end-by *1 (duration 5 :days)) -=> # +(jt/move-end-by *1 (jt/duration 5 :days)) +;=> # -(contains? *1 (offset-date-time 2015 1 1)) -=> false +(jt/contains? *1 (jt/offset-date-time 2015 1 1)) +;=> false ``` #### Joda-Time -Bonus! if you have Joda Time on the classpath (either directly, or via +Bonus! If you have Joda Time on the classpath (either directly, or via `clj-time`), you can seamlessly convert from Joda Time to Java Time types: ```clojure (java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime) -=> {:cost 2.0, - :path [[# - #] - [# - #]]} +;=> {:cost 2.0, +; :path [[# +; #] +; [# +; #]]} -(offset-time (org.joda.time.DateTime/now)) -=> # +(jt/offset-time (org.joda.time.DateTime/now)) +;=> # ``` Clojure 1.9 added an [Inst](https://clojuredocs.org/clojure.core/inst_q) @@ -451,7 +471,7 @@ default. If you're stuck on Joda-Time, you can extend the using the following: ```clojure -(java-time/when-joda-time-loaded +(jt/when-joda-time-loaded (extend-type org.joda.time.ReadableInstant Inst (inst-ms* [inst] (.getMillis inst)))) ``` @@ -463,43 +483,43 @@ the `Inst` protocol and the Joda-Time types are external to the library. Java Time introduced a concept of `Clock` - a time entity which can seed the dates, times and zones. However, there's no built-in facility which would allow -you to influence the date-times created using default constructors ala Joda's +you to influence the date-times created using default constructors à la Joda's `DateTimeUtils/setCurrentMillisSystem`. Clojure.Java-Time tries to fix that with the `with-clock` macro and the corresponding `with-clock-fn` function: ```clojure -(zone-id) -=> # +(jt/zone-id) +;=> # -(with-clock (system-clock "UTC") - (zone-id)) -=> # +(jt/with-clock (jt/system-clock "UTC") + (jt/zone-id)) +;=> # ``` In addition to the built-in `java.time` clocks, we provide a Mock clock which can be very handy in testing: ```clojure -(def clock (mock-clock 0 "UTC")) -=> #'user/clock +(def clock (jt/mock-clock 0 "UTC")) +;=> #'user/clock -(with-clock clock - (j/instant)) -=> #object[java.time.Instant "1970-01-01T00:00:00Z"] +(jt/with-clock clock + (jt/instant)) +;=> #object[java.time.Instant "1970-01-01T00:00:00Z"] -(advance-clock! clock (plus (hours 5) (minutes 20))) -=> nil +(jt/advance-clock! clock (jt/plus (jt/hours 5) (jt/minutes 20))) +;=> nil -(with-clock clock - (j/instant)) -=> #object[java.time.Instant "1970-01-01T05:20:00Z"] +(jt/with-clock clock + (jt/instant)) +;=> #object[java.time.Instant "1970-01-01T05:20:00Z"] -(set-clock! clock 0) -=> nil +(jt/set-clock! clock 0) +;=> nil -(with-clock clock - (j/instant)) -=> #object[java.time.Instant "1970-01-01T00:00:00Z"] +(jt/with-clock clock + (jt/instant)) +;=> #object[java.time.Instant "1970-01-01T00:00:00Z"] ``` Clock overrides works for all of the date-time types. @@ -512,48 +532,48 @@ via the `java-time.repl` ns: ```clojure (java-time.repl/show-fields) -=> (:aligned-day-of-week-in-month - :aligned-day-of-week-in-year - :aligned-week-of-month - :aligned-week-of-year - :am-pm-of-day - :clock-hour-of-am-pm - ...) +;=> (:aligned-day-of-week-in-month +; :aligned-day-of-week-in-year +; :aligned-week-of-month +; :aligned-week-of-year +; :am-pm-of-day +; :clock-hour-of-am-pm +; ...) ``` ```clojure (java-time.repl/show-units) -=> (:centuries - :days - :decades - :eras - :forever - :half-days - ...) +;=> (:centuries +; :days +; :decades +; :eras +; :forever +; :half-days +; ...) ``` You can obtain any field/unit like this: ```clojure -(field :year) -=> #object[java.time.temporal.ChronoField "Year"] +(jt/field :year) +;=> #object[java.time.temporal.ChronoField "Year"] -(unit :days) -=> #object[java.time.temporal.ChronoUnit "Days"] +(jt/unit :days) +;=> #object[java.time.temporal.ChronoUnit "Days"] -(field (local-date 2015) :year) -=> #object[java.time.temporal.ChronoField "Year"] +(jt/field (jt/local-date 2015) :year) +;=> #object[java.time.temporal.ChronoField "Year"] ``` You can obtain all of the fields/units of the temporal entity: ```clojure -(fields (local-date)) -=> {:proleptic-month #object[java.time.temporal.ChronoField ...} +(jt/fields (jt/local-date)) +;=> {:proleptic-month #object[java.time.temporal.ChronoField ...} -(units (duration)) -=> {:seconds #object[java.time.temporal.ChronoUnit "Seconds"], - :nanos #object[java.time.temporal.ChronoUnit "Nanos"]} +(jt/units (jt/duration)) +;=> {:seconds #object[java.time.temporal.ChronoUnit "Seconds"], +; :nanos #object[java.time.temporal.ChronoUnit "Nanos"]} ``` By themselves the fields and units aren't very interesting. You can get the @@ -561,14 +581,14 @@ range of valid values for a field and a duration between two dates, but that's about it: ```clojure -(range (field :year)) -=> #object[java.time.temporal.ValueRange "-999999999 - 999999999"] +(jt/range (jt/field :year)) +;=> #object[java.time.temporal.ValueRange "-999999999 - 999999999"] -(range (field :day-of-month)) -=> #object[java.time.temporal.ValueRange "1 - 28/31"] +(jt/range (jt/field :day-of-month)) +;=> #object[java.time.temporal.ValueRange "1 - 28/31"] -(time-between (local-date 2015 9) (local-date 2015 9 28) :days) -=> 27 +(jt/time-between (jt/local-date 2015 9) (jt/local-date 2015 9 28) :days) +;=> 27 ``` Fields and units become interesting in conjunction with properties. Java-Time @@ -578,23 +598,23 @@ Java's. In Clojure, properties allow expressing time entity modifications and queries uniformly across all of the entity types. ```clojure -(def prop (property (local-date 2015 2 28) :day-of-month)) -=> #java_time.temporal.TemporalFieldProperty{...} +(def prop (jt/property (jt/local-date 2015 2 28) :day-of-month)) +;=> #java_time.temporal.TemporalFieldProperty{...} -(value prop) -=> 28 +(jt/value prop) +;=> 28 -(with-min-value prop) -=> #object[java.time.LocalDate "2015-02-01"] +(jt/with-min-value prop) +;=> #object[java.time.LocalDate "2015-02-01"] -(with-value prop 20) -=> #object[java.time.LocalDate "2015-02-20"] +(jt/with-value prop 20) +;=> #object[java.time.LocalDate "2015-02-20"] -(with-max-value prop) -=> #object[java.time.LocalDate "2015-02-28"] +(jt/with-max-value prop) +;=> #object[java.time.LocalDate "2015-02-28"] -(properties (local-date 2015 9 28)) -=> {:proleptic-month #java_time.temporal.TemporalFieldProperty{...}, ...} +(jt/properties (jt/local-date 2015 9 28)) +;=> {:proleptic-month #java_time.temporal.TemporalFieldProperty{...}, ...} ``` ## Implementation Details @@ -617,19 +637,19 @@ You can play with the conversion graph using the following helpers: ```clojure (java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime) -=> {:cost 2.0, - :path [[# - #] - [# - #]]} +;=> {:cost 2.0, +; :path [[# +; #] +; [# +; #]]} (java-time.repl/show-graph) -=> {1 - {org.threeten.extra.DayOfYear - [[#object[java_time.graph.Types "[java.lang.Number]"] - #object[java_time.graph.Conversion "Cost:1.0"]]], - java.lang.Number - [[#object[java_time.graph.Types "[java.time.Instant]"] - #object[java_time.graph.Conversion "Cost:1.0"]] - ... -``` +;=> {1 +; {org.threeten.extra.DayOfYear +; [[#object[java_time.graph.Types "[java.lang.Number]"] +; #object[java_time.graph.Conversion "Cost:1.0"]]], +; java.lang.Number +; [[#object[java_time.graph.Types "[java.time.Instant]"] +; #object[java_time.graph.Conversion "Cost:1.0"]] +; ...}} +``` \ No newline at end of file diff --git a/bb.edn b/bb.edn new file mode 100644 index 0000000..b200caa --- /dev/null +++ b/bb.edn @@ -0,0 +1,13 @@ +{:paths ["src" "test" "bin"] + :tasks + {:requires ([babashka.fs :as fs] + [babashka.process :as p :refer [process]] + [babashka.wait :as wait]) + nrepl (let [port (with-open [sock (java.net.ServerSocket. 0)] (.getLocalPort sock)) + proc (process (str "bb nrepl-server " port) {:inherit true})] + (wait/wait-for-port "localhost" port) + (spit ".nrepl-port" port) + (fs/delete-on-exit ".nrepl-port") + (deref proc)) + test (require 'bb-test-runner)}} + diff --git a/bin/-release-readme+changelog.clj b/bin/-release-readme+changelog.clj new file mode 100755 index 0000000..cf0b414 --- /dev/null +++ b/bin/-release-readme+changelog.clj @@ -0,0 +1,53 @@ +#!/usr/bin/env bb +(ns -release-readme+changelog + "Update README.md and CHANGELOG.md with the current version in project.clj. + + Usage: ./bin/-release-readme+changelog.clj" + (:require [clojure.string :as str])) + +(defn get-project-version [] + {:post [(string? %) + (seq %)]} + (let [project-version-prefix "(defproject clojure.java-time \"" + project-version-suffix "\""] + (some #(when (and (str/starts-with? % project-version-prefix) + (str/ends-with? % project-version-suffix)) + (subs % (count project-version-prefix) (- (count %) (count project-version-suffix)))) + (str/split-lines (slurp "project.clj"))))) + +(defn update-readme [project-version slurped-readme] + (let [replace-version-around (volatile! + #{{:prefix "clojure.java-time/clojure.java-time {:mvn/version \"" + :suffix "\"}"} + {:prefix "[clojure.java-time \"" + :suffix "\"]"}}) + res (str/join "\n" + (map (fn [s] + (if-some [matching (first (filter #(and (str/starts-with? s (:prefix %)) + (str/ends-with? s (:suffix %))) + @replace-version-around))] + (do (vswap! replace-version-around disj matching) + (str (:prefix matching) project-version (:suffix matching))) + s)) + (str/split-lines slurped-readme)))] + (assert (empty? @replace-version-around) + (str "Failed to replace: " @replace-version-around)) + res)) + +(assert (= "# Readme\n\n## Dependency\n\nclojure.java-time/clojure.java-time {:mvn/version \"1.0.0\"}\n\n[clojure.java-time \"1.0.0\"]" + (update-readme "1.0.0" + "# Readme\n\n## Dependency\n\nclojure.java-time/clojure.java-time {:mvn/version \"0.5.0\"}\n\n[clojure.java-time \"0.5.0\"]"))) + +(defn update-changelog [project-version slurped-changelog] + (str/replace slurped-changelog "## NEXT\n" (format "## NEXT\n\n## %s\n" project-version))) + +(assert (= "# Changelog\n\n## NEXT\n\n## 1.0.0\n\n- a release note" + (update-changelog "1.0.0" "# Changelog\n\n## NEXT\n\n- a release note"))) + +(defn -main [] + (let [project-version (get-project-version)] + (spit "README.md" (update-readme project-version (slurp "README.md"))) + (spit "CHANGELOG.md" (update-changelog project-version (slurp "CHANGELOG.md"))))) + +(when (= *file* (System/getProperty "babashka.file")) + (apply -main *command-line-args*)) diff --git a/bin/bb-test-runner.sh b/bin/bb-test-runner.sh new file mode 100755 index 0000000..b1841ea --- /dev/null +++ b/bin/bb-test-runner.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +set -e +bb --debug --file ./bin/bb-test-runner.clj diff --git a/bin/bb_test_runner.clj b/bin/bb_test_runner.clj new file mode 100644 index 0000000..71a6b79 --- /dev/null +++ b/bin/bb_test_runner.clj @@ -0,0 +1,40 @@ +;; run via ./bin/bb-test-runner.sh +(ns bb-test-runner + (:require [clojure.test :as t] + [babashka.classpath :as cp])) + +(def require-nsyms ['java-time.joda + 'java-time.core + 'java-time.properties + 'java-time.util + 'java-time.temporal + 'java-time.amount + 'java-time.zone + 'java-time.single-field + 'java-time.local + 'java-time.chrono + 'java-time.convert + 'java-time.sugar + 'java-time.seqs + 'java-time.adjuster + 'java-time.interval + 'java-time.format + 'java-time.clock + 'java-time.pre-java8 + 'java-time + ]) + +(def test-nsyms ['java-time-test + 'java-time.graph-test]) + +(some->> (seq (concat require-nsyms test-nsyms)) + (apply require)) + +(def test-results + (apply t/run-tests test-nsyms)) + +(def failures-and-errors + (let [{:keys [fail error]} test-results] + (min 1 (+ fail error)))) + +(System/exit failures-and-errors) diff --git a/bin/codox.sh b/bin/codox.sh index 756b98e..15c8f3c 100755 --- a/bin/codox.sh +++ b/bin/codox.sh @@ -10,8 +10,7 @@ fi rm -rf ./doc git checkout $1 -lein with-profile -user codox -cp -r ./target/doc ./docs +lein doc git checkout master git add . diff --git a/bin/release.sh b/bin/release.sh new file mode 100755 index 0000000..535579c --- /dev/null +++ b/bin/release.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# Releases the current version in project.clj and bump to the next :minor version. +# Updates changelog and readme to released version. +# Does not push anything if deployment fails. +# If deployment fails, reset to origin/master and remove the latest tag to reset local repo. +lein release :minor diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..ccd9a31 --- /dev/null +++ b/deps.edn @@ -0,0 +1 @@ +{:paths ["src"]} diff --git a/dev/user.clj b/dev/user.clj index 8bc23a2..c48e22b 100644 --- a/dev/user.clj +++ b/dev/user.clj @@ -2,7 +2,7 @@ (:require [clojure.tools.namespace.repl :as repl] [criterium.core :as crit] [taoensso.timbre :as timbre] - [taoensso.timbre.profiling :as profiling :refer (pspy pspy* profile defnp p p*)])) + [taoensso.tufte :as profiling :refer (pspy profile defnp p)])) (defn go [] (set! *warn-on-reflection* false) diff --git a/docs/CHANGELOG.html b/docs/CHANGELOG.html new file mode 100644 index 0000000..85aa579 --- /dev/null +++ b/docs/CHANGELOG.html @@ -0,0 +1,157 @@ + +Changelog

Changelog

+

NEXT

+ +

1.4.2

+
    +
  • #105: fix not-{before,after}? on unconverted values
  • +
  • a consequence of fixing #104
  • +
  • add java-time.api/= for equality of times (with conversions)
  • +
  • add support to intermix unconverted values in comparison operations after first argument
  • +
  • supported by {before,after}?, not-{before,after}?, j/=, and aliases of those ops
  • +
  • examples: +
      +
    • (j/< (j/day-of-week :thursday) :saturday :sunday)
    • +
    • (j/<= (j/day-of-week :thursday) :thursday (j/day-of-week :saturday) :sunday)
    • +
    • (j/= (j/day-of-week :thursday) :thursday (j/day-of-week :thursday) :thursday)
    • +
    +
  • +
+

1.4.1

+
    +
  • #104: fix transivitity of not-{before,after}? when called with intervals
  • +
+

1.4.0

+
    +
  • #98: fix not-before? and not-after? with one or more than two arguments
  • +
  • new aliases
  • +
  • java-time.api/+ aliases java-time.api/plus
  • +
  • java-time.api/- aliases java-time.api/minus
  • +
  • java-time.api/neg? aliases java-time.api/negative?
  • +
  • java-time.api/< aliases java-time.api/before?
  • +
  • java-time.api/> aliases java-time.api/after?
  • +
  • java-time.api/<= aliases java-time.api/not-after?
  • +
  • java-time.api/>= aliases java-time.api/not-before?
  • +
+

1.3.0

+ +

1.2.0

+ +

1.1.0

+

Due to #91, the main java-time namespace has been deprecated. A new namespace java-time.api has been created

+

Note that this change is entirely optional—java-time and java-time.api will continue to be in sync and may coexist.

+

See the docstring for java-time for more details.

+

1.0.0

+

Released 2022-11-24.

+

New Features

+
    +
  • Previously, Intervals were only allowed to the left of Instants in {before,after}?. Now they can be freely intermixed.
  • +
+

Fixed

+
    +
  • #78(liquidz): Add missing chrono fields (v0.3.3 has breaking changes)
  • +
  • #81(terop): Remove clj-tuple - no advantages over Clojure vector anymore
  • +
  • #52: Fix before/after on Intervals
  • +
  • #83(imrekoszo): Exclude clojure.core/abs
  • +
+

Enhancements

+
    +
  • add docstrings to all java-time fns
  • +
  • support clj-kondo in java-time ns by adding :arglists to all vars
  • +
+

Internal

+
    +
  • Deprecate java-time.util/get-static-fields-of-type
  • +
  • Remove java-time.potemkin.namespaces
  • +
+

0.3.3

+

New Features

+
    +
  • #71(brettrowberry): not-after? and not-before?
  • +
  • #40(davidneu)/#61(puredanger): added/fixed deps.edn
  • +
+

Fixed

+
    +
  • #72(FieryCod): working with GraalVM
  • +
  • #29(danieldroit): conversion graph construction edge case
  • +
  • #60(robdaemon): locales can mess up predefined-formatters
  • +
  • #51(jimpil): remove reflection during load - improves load time
  • +
+

Docs

+
    +
  • #27(emlin)
  • +
  • #35(thobbs)
  • +
  • #36(holyjak)
  • +
  • #38(ProjectFrank)
  • +
  • #39(sashary)
  • +
  • #48(bpringe)
  • +
  • #56,#57(green-coder)
  • +
  • #63(vandr0iy)
  • +
  • #54,#31,#24
  • +
+

0.3.2

+

New Features

+
    +
  • zone-id? predicate
  • +
  • set-clock! - sets the mocked clock value to the supplied instant
  • +
  • when-joda-time-loaded - macro which runs code when Joda-Time is on the classpath
  • +
  • instant->sql-timestamp - produce a java.sql.Timestamp from an Instant-like object
  • +
  • as support for two-field Time entities #21, courtesy Larry Jones
  • +
+

0.3.1

+

New Features

+
    +
  • clock? predicate
  • +
  • mock-clock - returns a mocked instance of java.time.Clock.
  • +
+

0.3.0

+

Breaking changes

+
    +
  • to-sql-date converts anything convertible to LocalDate into a java.sql.Date. Previously to-sql-date returned a java.util.Date (bug).
  • +
  • #10 to-sql-timestamp stopped accepting an instant and starting accepting local date time. I mistakenly assumed that java.sql.Timestamp/from(Instant) was deprecated.
  • +
+

New Features

+

Please see a new section within README - Legacy Date-Time Types

+
    +
  • java-date, sql-date, sql-timestamp, sql-time - functions which produce the java.util.* date-time objects.
  • +
  • #5 automatic conversions: +
      +
    • java.sql.Date -> java.time.LocalDate
    • +
    • java.sql.Timestamp -> java.time.LocalDateTime
    • +
    • java.sql.Time -> java.time.LocalTime
    • +
    +
  • +
  • deprecated to-java-date/to-sql-date/to-sql-timestamp
  • +
+

0.2.2

+

Fixed

+
    +
  • Wrong primitive type annotation on to-millis-from-epoch, see Eastwood docs for the explanation.
  • +
+

0.2.1

+

Fixed

+
    +
  • #1: Reflection warnings in two-field time entity constructors
  • +
  • #2: Ordered implementation for java.time.Instant
  • +
+

0.2.0

+

Breaking changes

+
    +
  • zoned-date-time doesn’t accept the zone id as the last argument
  • +
  • offset-date-time/offset-time doesn’t accept offset id as the last argument
  • +
+

New features

+
    +
  • with-offset/with-offset-same-instant for offset manipulation
  • +
  • with-zone/with-zone-same-instant for zone manipulation
  • +
+
\ No newline at end of file diff --git a/docs/README.html b/docs/README.html index 8615562..a2a6c8d 100644 --- a/docs/README.html +++ b/docs/README.html @@ -1,351 +1,429 @@ -Clojure.Java-Time

Clojure.Java-Time

-

Build Status

+Clojure.Java-Time

Clojure.Java-Time

+

Clojars Project

A Clojure wrapper for Java 8 Date-Time API.

-

Rationale

+
+

Note: This library has no relation to Clojure’s (or Java’s) core team. It’s naming is legacy and preserved for backwards compatibility reasons.

+
+

Rationale

Main goals:

    -
  • Provide a consistent API for common operations with instants, date-times, zones and periods.
  • -
  • Provide an escape hatch from Java types to clojure data structures.
  • -
  • Avoid reflective calls.
  • -
  • Provide an entry point into Java-Time by freeing the user from importing most of the Java-Time classes.
  • +
  • Provide a consistent API for common operations with instants, date-times, zones and periods.
  • +
  • Provide an escape hatch from Java types to clojure data structures.
  • +
  • Avoid reflective calls.
  • +
  • Provide an entry point into Java-Time by freeing the user from importing most of the Java-Time classes.

Why use Clojure.Java-Time over clj-time or Clojure.Joda-Time?

    -
  • You don’t want to have a dependency on the Joda-Time library
  • -
  • You already use Java 8
  • -
  • You prefer as little Java interop code as possible
  • +
  • You don’t want to have a dependency on the Joda-Time library
  • +
  • You already use Java 8
  • +
  • You prefer as little Java interop code as possible

This library employs a structured and comprehensive approach to exposing the Java 8 Date-Time API to the Clojure world. It’s very similar to Clojure.Joda-Time in its design goals and overall feeling, so if you ever used that you will feel at home!

-

Documentation

+

Why use Clojure.Java-Time over cljc.java-time with tick?

    -
  • API
  • +
  • You only plan on running on the JVM
  • +
  • You prefer a single require over multiple ones
-

What’s different in Java Time API?

-

If you already used Joda Time before you might think: “What in the world could they do better?”. After all, Joda-Time already provides a pretty comprehensive set of tools for dealing with time-related concepts. Turns out, it’s a tad more complicated than it has to be. Also, a few concepts have faulty designs which lead to hard to fix bugs and misuse. You can see the birds-eye view of changes and some of the rationale on the authors’ (Stephen Colebourne) blog:

+

I don’t see any reasons except for aesthetical pleasure and existing knowledge to choose one over the other. However, I have neither used or benchmarked Cljc.Java-Time and Tick so my endorsement is purely on the merits of a broader feature set.

+

Documentation

+

What’s different in Java Time API?

+

If you already used Joda Time before you might think: “What in the world could they do better?”. After all, Joda-Time already provides a pretty comprehensive set of tools for dealing with time-related concepts. Turns out, it’s a tad more complicated than it has to be. Also, a few concepts have faulty designs which lead to hard to fix bugs and misuse. You can see the birds-eye view of changes and some of the rationale on the author’s (Stephen Colebourne) blog:

+

You can also take a look at a comprehensive comparison by the Time4J authors.

-

Usage

-

Add the following dependency to your project.clj or build.boot:

-
[clojure.java-time "0.3.0"]
-
-

The API of the Clojure.Java-Time consists of one namespace, namely java-time. For the purposes of this guide, we will use the main namespace:

-
(refer-clojure :exclude [range iterate format max min])
-(use 'java-time)
-
-

Concept run-through

-

Java Time API may seem daunting. Instead of a single java.util.Date you have a ZonedDateTime, OffsetDateTime, LocalDateTime, Instant, and other types. You would be well served by reading the official documentation for the Java Time API, but we’ll also do a quick run-through here.

-

Local Dates

-

LocalDate, LocalTime and LocalDateTime are used to represent a date, time and date-time respectively without an offset or a timezone. The local time entities are used to represent human-based dates/times. They are a good fit for representing the time of various events:

+

Usage

+

Add the following dependency to your deps.edn:

+
clojure.java-time/clojure.java-time {:mvn/version "1.4.2"}
+
+

or to your project.clj or build.boot:

+
[clojure.java-time "1.4.2"]
+
+

The API of the Clojure.Java-Time consists of one namespace, namely java-time.api. For the purposes of this guide, we will require the main namespace:

+
(require '[java-time.api :as jt]
+         ;; for REPL experimentation
+         'java-time.repl)
+
+

Concept run-through

+

The Java Time API may seem daunting. Instead of a single java.util.Date you have a ZonedDateTime, OffsetDateTime, LocalDateTime, Instant, and other types. You would be well served by reading the official documentation for the Java Time API, but we’ll also do a quick run-through here.

+

Local Dates and/or Times

+

LocalDate, LocalTime and LocalDateTime are used to represent a date, time and date-time respectively without an offset or a time zone. The local time entities are used to represent human-based dates/times. They are a good fit for representing the time of various events:

+
    +
  • LocalDate - birthday, holiday
      -
    • LocalDate - birthday, holiday
    • -
    • LocalTime - bus schedule, opening time of a shop
    • -
    • LocalDateTime - start of a competition
    • +
    • see jt/local-date
    -

    A local date/time can be created as you’d expect:

    -
    (local-date 2015 10)
    -=> #<java.time.LocalDate 2015-10-01>
    +
  • +
  • LocalTime - bus schedule, opening time of a shop + +
  • +
  • LocalDateTime - start of a competition + +
  • +
+

Example usage:

+
(jt/local-date 2015 10)
+;=> #<java.time.LocalDate 2015-10-01>
 
-(local-time 10)
-=> #<java.time.LocalTime 10:00>
+(jt/local-time 10)
+;=> #<java.time.LocalTime 10:00>
 
-(local-date-time 2015 10)
-=> #<java.time.LocalDateTime 2015-10-01T00:00>
+(jt/local-date-time 2015 10)
+;=> #<java.time.LocalDateTime 2015-10-01T00:00>
 
-

Zoned Dates

-

There are two types which deal with zones: OffsetDateTime and ZonedDateTime. They do pretty much what you would expect from their name. You can think of the Offset time as a more concrete version of the Zoned time. For example, the same timezone can have different offsets throughout the year due to DST or governmental regulations.

-
(offset-time 10)
-=> #<java.time.OffsetTime 10:00+01:00>
+

Zoned Dates

+

There are two types which deal with zones: * OffsetDateTime * see jt/offset-date-time * ZonedDateTime * see jt/zoned-date-time

+

They do pretty much what you would expect from their name. You can think of the Offset time as a more concrete version of the Zoned time. For example, the same time zone can have different offsets throughout the year due to DST or governmental regulations.

+
(jt/offset-time 10)
+;=> #<java.time.OffsetTime 10:00+01:00>
 
-(offset-date-time 2015 10)
-=> #<java.time.OffsetDateTime 2015-10-01T10:00+01:00>
+(jt/offset-date-time 2015 10)
+;=> #<java.time.OffsetDateTime 2015-10-01T10:00+01:00>
 
-(zoned-date-time 2015 10)
-=> #<java.time.ZonedDateTime 2015-10-01T10:00+01:00[Europe/London]>
+(jt/zoned-date-time 2015 10)
+;=> #<java.time.ZonedDateTime 2015-10-01T10:00+01:00[Europe/London]>
 
-

Offset/Zone times only take the offset/zone as the last arguments for the maximum arity constructor. You can influence the zone/offset by using the with-zone or with-offset functions, like so:

-
(with-zone (zoned-date-time 2015 10) "UTC")
-=> #<java.time.ZonedDateTime 2015-10-01T00:00Z[UTC]>
+

Offset/Zone times only take the offset/zone as the last arguments for the maximum arity constructor. You can influence the zone/offset by using the jt/with-zone or jt/with-offset functions, like so:

+
(jt/with-zone (jt/zoned-date-time 2015 10) "UTC")
+;=> #<java.time.ZonedDateTime 2015-10-01T00:00Z[UTC]>
 
-(with-zone-same-instant (zoned-date-time 2015 10) "UTC")
-=> #<java.time.ZonedDateTime 2015-09-30T23:00Z[UTC]>
+(jt/with-zone-same-instant (jt/zoned-date-time 2015 10) "UTC")
+;=> #<java.time.ZonedDateTime 2015-09-30T23:00Z[UTC]>
 
-(with-clock (system-clock "UTC")
-  (zoned-date-time 2015 10))
-=> #<java.time.ZonedDateTime 2015-10-01T00:00Z[UTC]>
+(jt/with-clock (jt/system-clock "UTC")
+  (jt/zoned-date-time 2015 10))
+;=> #<java.time.ZonedDateTime 2015-10-01T00:00Z[UTC]>
 
-

Instant

+

Instant

An Instant is used to generate a time stamp representing machine time. It doesn’t have an offset or a time zone. You can think of it as of a number of milliseconds since epoch (1970-01-01T00:00:00Z). An instant is directly analogous to java.util.Date:

-
user=> (instant)
-#<java.time.Instant "2015-09-26T05:25:48.667Z">
+
(jt/instant)
+;=> #<java.time.Instant "2015-09-26T05:25:48.667Z">
 
-user=> (java.util.Date.)
-#inst "2015-09-26T05:25:50.118-00:00"
+(java.util.Date.)
+;=> #inst "2015-09-26T05:25:50.118-00:00"
 

Every other date entity can be converted to an instant (local ones will require an additional zone information).

-

Period and Duration

+

Period and Duration

Java Time Period entities are considerably simpler than the Joda-Time periods. They are fixed containers of years, months and days. You can use them to represent any period of time with a granularity larger or equal to a single day. Duration, on the other hand, represents a standard duration less than or equal to a single standard (24-hour) day.

-

Caution

-

The current incarnation of the library is quite slow while calling the 2-3 arity zoned-date-time/offset-time/offset-date-time constructors. If you need predictable latency on the first call, please warm the constructors you are going to use by using them in a ‘warm-up phase’, e.g.:

-
(defn warm-up []
-  (zoned-date-time 2015 1 1)
-  (zoned-date-time 2015 1)
-  (zoned-date-time 2015))
-
-

Only the types of the arguments matter, not the values!

-

An appetizer

+

Caution

+

The current incarnation of the library is relatively slow while calling the 2-3 arity zoned-date-time/offset-time/offset-date-time constructors for the first time in a given Clojure runtime. If you need predictable latency at the time of the first call in your business logic, please warm the constructors you are going to use up by calling them beforehand, e.g.:

+
(defn warm-up []
+  (jt/zoned-date-time 2015 1 1)
+  (jt/zoned-date-time 2015 1)
+  (jt/zoned-date-time 2015))
+
+

The “constructor” here refers to an arity of a function together with its type signature. For example, a (jt/zoned-date-time 2015) and (jt/zoned-date-time (jt/system-clock)) are different constructors.

+

An appetizer

First, let’s do a quick run through common use cases.

What is the current date?

-
(def now (local-date))
-=> #object[java.time.LocalDate "2015-09-27"]
+
(def now (jt/local-date))
+;=> #object[java.time.LocalDate "2015-09-27"]
 

What’s the next day?

-
(plus now (days 1))
-=> #object[java.time.LocalDate "2015-09-28"]
+
(jt/plus now (jt/days 1))
+;=> #object[java.time.LocalDate "2015-09-28"]
 

The previous day?

-
(minus now (days 1))
-=> #object[java.time.LocalDate "2015-09-28"]
+
(jt/minus now (jt/days 1))
+;=> #object[java.time.LocalDate "2015-09-26"]
 
-

Three next days?

-
(take 3 (iterate plus now (days 1)))
-=> (#object[java.time.LocalDate "2015-09-28"]
-    #object[java.time.LocalDate "2015-09-29"]
-    #object[java.time.LocalDate "2015-09-30"])
+

Three days starting at now?

+
(take 3 (jt/iterate jt/plus now (jt/days 1)))
+;=> (#object[java.time.LocalDate "2015-09-27"]
+;    #object[java.time.LocalDate "2015-09-28"]
+;    #object[java.time.LocalDate "2015-09-29"])
 

When is the first Monday in month?

-
(adjust now :first-in-month :monday)
-=> #object[java.time.LocalDate "2015-09-07"]
+
(jt/adjust now :first-in-month :monday)
+;=> #object[java.time.LocalDate "2015-09-07"]
 

Date with some of its fields truncated:

-
(truncate-to (local-date-time 2015 9 28 10 15) :days)
-=> #object[java.time.LocalDateTime "2015-09-28T00:00"]
+
(jt/truncate-to (jt/local-date-time 2015 9 28 10 15) :days)
+;=> #object[java.time.LocalDateTime "2015-09-28T00:00"]
 

Date-time adjusted to the given hour:

-
(adjust (local-date-time 2015 9 28 10 15) (local-time 6))
-=> #object[java.time.LocalDateTime "2015-09-28T06:00"]
+
(jt/adjust (jt/local-date-time 2015 9 28 10 15) (jt/local-time 6))
+;=> #object[java.time.LocalDateTime "2015-09-28T06:00"]
 

The latest of the given dates?

-
(max (local-date 2015 9 20) (local-date 2015 9 28) (local-date 2015 9 1))
-=> #object[java.time.LocalDate "2015-09-28"]
+
(jt/max (jt/local-date 2015 9 20) (jt/local-date 2015 9 28) (jt/local-date 2015 9 1))
+;=> #object[java.time.LocalDate "2015-09-28"]
 

The shortest of the given durations?

-
(min (duration 10 :seconds) (duration 5 :hours) (duration 3000 :millis))
-=> #object[java.time.Duration "PT3S"]
+
(jt/min (jt/duration 10 :seconds) (jt/duration 5 :hours) (jt/duration 3000 :millis))
+;=> #object[java.time.Duration "PT3S"]
 

Get the year field out of the date:

-
(as (local-date 2015 9 28) :year)
-=> 2015
+
(jt/as (jt/local-date 2015 9 28) :year)
+;=> 2015
 

Get multiple fields:

-
(as (local-date 2015 9 28) :year :month-of-year :day-of-month)
-=> (2015 9 28)
+
(jt/as (jt/local-date 2015 9 28) :year :month-of-year :day-of-month)
+;=> (2015 9 28)
 

Get the duration in a different unit:

-
java-time> (plus (hours 3) (minutes 2))
-#object[java.time.Duration "PT3H2M"]
-java-time> (as *1 :minutes)
-182
+
(jt/plus (jt/hours 3) (jt/minutes 2))
+;=> #object[java.time.Duration "PT3H2M"]
+
+(jt/as *1 :minutes)
+;=> 182
 

Format a date:

-
(format "MM/dd" (zoned-date-time 2015 9 28))
-=> "09/28"
+
(jt/format "MM/dd" (jt/zoned-date-time 2015 9 28))
+;=> "09/28"
 

Parse a date:

-
(local-date "MM/yyyy/dd" "09/2015/28")
-=> #object[java.time.LocalDate "2015-09-28"]
+
(jt/local-date "MM/yyyy/dd" "09/2015/28")
+;=> #object[java.time.LocalDate "2015-09-28"]
 

Zoned date-times and offset date-times/times always take the zone/offset as the last argument. Offsets can be specified as float values:

-
(zone-offset +1.5)
-=> #<java.time.ZoneOffset +01:30>
+
(jt/zone-offset +1.5)
+;=> #<java.time.ZoneOffset +01:30>
 
-(zone-offset -1.5)
-=> #<java.time.ZoneOffset -01:30>
+(jt/zone-offset -1.5)
+;=> #<java.time.ZoneOffset -01:30>
 
-

Conversions

-

Time entities can be converted to other time entities if the target contains less information, e.g. (assuming we’re in UTC timezone):

-
(zoned-date-time (offset-date-time 2015 9 28 1))
-=> #object[java.time.ZonedDateTime "2015-09-28T01:00Z"]
+

Compare dates:

+
(jt/before? (jt/year 2020) (jt/year 2021))
+;=> true
 
-(instant (offset-date-time 2015 9 28 1))
-=> #object[java.time.Instant "2015-09-28T01:00:00Z"]
+(jt/after? (jt/year 2021) (jt/year 2021))
+;=> false
 
-(offset-time (offset-date-time 2015 9 28 1))
-=> #object[java.time.OffsetTime "01:00Z"]
+(let [expiration-date (jt/year 2010)
+      purchase-date (jt/year 2010)]
+  (jt/not-before? expiration-date purchase-date))
+;=> true
+
+(let [start-date (jt/year 2011)
+      cutoff-date (jt/year 2010)]
+  (jt/not-after? start-date cutoff-date))
+;=> false
+
+

Conversions

+

Time entities can be converted to other time entities if the target contains less information, e.g. (assuming we’re in UTC time zone):

+
(jt/zoned-date-time (jt/offset-date-time 2015 9 28 1))
+;=> #object[java.time.ZonedDateTime "2015-09-28T01:00Z"]
 
-(local-date-time (offset-date-time 2015 9 28 1))
-=> #object[java.time.LocalDateTime "2015-09-28T01:00"]
+(jt/instant (jt/offset-date-time 2015 9 28 1))
+;=> #object[java.time.Instant "2015-09-28T01:00:00Z"]
 
-(local-time (offset-time 1))
-=> #object[java.time.LocalTime 0x3a3cd6d5 "01:00"]
+(jt/offset-time (jt/offset-date-time 2015 9 28 1))
+;=> #object[java.time.OffsetTime "01:00Z"]
+
+(jt/local-date-time (jt/offset-date-time 2015 9 28 1))
+;=> #object[java.time.LocalDateTime "2015-09-28T01:00"]
+
+(jt/local-time (jt/offset-time 1))
+;=> #object[java.time.LocalTime 0x3a3cd6d5 "01:00"]
+
+

Converting an Instant to ZonedDateTime requires a time zone:

+
(jt/zoned-date-time (jt/instant 100) "UTC")
+;=> #object[java.time.ZonedDateTime 0x291777c0 "1970-01-01T00:00:00.100Z[UTC]"]
 
-

Legacy Date-Time Types

+

Legacy Date-Time Types

Any date which can be converted to an instant, can also be converted to a java.util.Date:

-
(java-date (zoned-date-time 2015 9 28))
-=> #inst "2015-09-27T22:00:00.000-00:00"
+
(jt/java-date (jt/zoned-date-time 2015 9 28))
+;=> #inst "2015-09-27T22:00:00.000-00:00"
 
-(java-date 50000)
-=> #inst "1970-01-01T00:00:50.000-00:00"
+(jt/java-date 50000)
+;=> #inst "1970-01-01T00:00:50.000-00:00"
 
-

An instance of java.util.Date serves the same purpose as the new java.time.Instant. It’s a machine timestamp which isn’t aware of the timezone. Please, do not get confused by the way it is printed by the Clojure printer - the UTC timezone is applied during formatting.

-

Sometimes you’ll have to work with the legacy java.sql.Date/Time/Timestamp types. The correspondence between the legacy types and the new Date-Time entities is as follows:

+

An instance of java.util.Date serves the same purpose as the new java.time.Instant. It’s a machine timestamp which isn’t aware of the time zone. Please, do not get confused by the way it is printed by the Clojure printer - the UTC time zone is applied during formatting.

+

Sometimes you’ll have to work with the legacy java.sql.{Date,Time,Timestamp} types. The correspondence between the legacy types and the new Date-Time entities is as follows:

    -
  • java.time.LocalDate - java.sql.Date
  • -
  • java.time.LocalDateTime - java.sql.Timestamp
  • -
  • java.time.LocalTime - java.sql.Time
  • +
  • java.sql.Date <-> java.time.LocalDate
  • +
  • java.sql.Timestamp <-> java.time.LocalDateTime
  • +
  • java.sql.Time <-> java.time.LocalTime
-
(sql-date 2015 9 28)
-=> #inst "2015-09-27T22:00:00.000-00:00"
+
(jt/sql-date 2015 9 28)
+;=> #inst "2015-09-27T22:00:00.000-00:00"
 
-(sql-timestamp 2015 9 28 10 20 30 4000000)
-=> #inst "2015-09-28T09:20:30.004-00:00"
+(jt/sql-timestamp 2015 9 28 10 20 30 4000000)
+;=> #inst "2015-09-28T09:20:30.004-00:00"
 
-(sql-time 10 20 30)
-=> #inst "1970-01-01T09:20:30.000-00:00"
+(jt/sql-time 10 20 30)
+;=> #inst "1970-01-01T09:20:30.000-00:00"
 
-

The results of the above calls get printed as #inst because all of the java.sql.Date/Time/Timestamp are subtypes of java.util.Date. Coincidentally, this makes it impossible to plug the java.sql.* types into the Clojure.Java-Time conversion graph.

+

The results of the above calls get printed as #inst because all of the java.sql.{Date,Time,Timestamp} are subtypes of java.util.Date. Coincidentally, this makes it impossible to plug the java.sql.* types into the Clojure.Java-Time conversion graph.

Conversions to the legacy types also go the other way around:

-
(j/local-date (j/sql-date 2015 9 28))
-#object[java.time.LocalDate "2015-09-28"]
+
(jt/local-date (jt/sql-date 2015 9 28))
+;=> #object[java.time.LocalDate "2015-09-28"]
 
-(j/local-date-time (j/sql-timestamp 2015 9 28 10 20 30 4000000))
-#object[java.time.LocalDateTime "2015-09-28T10:20:30.004"]
+(jt/local-date-time (jt/sql-timestamp 2015 9 28 10 20 30 4000000))
+;=> #object[java.time.LocalDateTime "2015-09-28T10:20:30.004"]
 
-(j/local-time (j/sql-time 10 20 30))
-#object[java.time.LocalTime "10:20:30"]
+(jt/local-time (jt/sql-time 10 20 30))
+;=> #object[java.time.LocalTime "10:20:30"]
 
-

Three-Ten Extra

-

If you add an optional [org.threeten/threeten-extra "0.9"] dependency to the project, you will get an Interval, AmPm, DayOfMonth, DayOfYear, Quarter and YearQuarter data types as well as a couple more adjusters.

+

Three-Ten Extra

+

If you add an optional [org.threeten/threeten-extra "1.2"] dependency to the project, you will get an Interval, AmPm, DayOfMonth, DayOfYear, Quarter and YearQuarter data types as well as a couple more adjusters.

An interval can be constructed from two entities that can be converted to instants:

-
(interval (offset-date-time 2015 1 1) (zoned-date-time 2016 1 1))
-=> #<org.threeten.extra.Interval 2015-01-01T00:00:00Z/2016-01-01T00:00:00Z>
+
(jt/interval (jt/offset-date-time 2015 1 1) (jt/zoned-date-time 2016 1 1))
+;=> #<org.threeten.extra.Interval 2015-01-01T00:00:00Z/2016-01-01T00:00:00Z>
 
-(move-start-by *1 (duration 5 :days))
-=> #<org.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-01T00:00:00Z>
+(jt/move-start-by *1 (jt/duration 5 :days))
+;=> #<org.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-01T00:00:00Z>
 
-(move-end-by *1 (duration 5 :days))
-=> #<org.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-06T00:00:00Z>
+(jt/move-end-by *1 (jt/duration 5 :days))
+;=> #<org.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-06T00:00:00Z>
+
+(jt/contains? *1 (jt/offset-date-time 2015 1 1))
+;=> false
+
+

Joda-Time

+

Bonus! If you have Joda Time on the classpath (either directly, or via clj-time), you can seamlessly convert from Joda Time to Java Time types:

+
(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)
+;=> {:cost 2.0,
+;    :path [[#<java_time.graph.Types@15e43c24 [org.joda.time.DateTime]>
+;            #<java_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]>]
+;           [#<java_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]>
+;            #<java_time.graph.Types@5360f6ae [java.time.OffsetTime]>]]}
 
-(contains? *1 (offset-date-time 2015 1 1))
-=> false
+(jt/offset-time (org.joda.time.DateTime/now))
+;=> #<java.time.OffsetTime 22:00:00.000000000-00:00>
 
-

Joda-Time

-

Bonus! if you have Joda Time on the classpath (either directly, or via clj-time), you can seamlessly convert from Joda Time to Java Time types:

-
(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)
-=> {:cost 2.0,
-    :path [[#<java_time.graph.Types@15e43c24 [org.joda.time.DateTime]>
-            #<java_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]>]
-           [#<java_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]>
-            #<java_time.graph.Types@5360f6ae [java.time.OffsetTime]>]]}
+

Clojure 1.9 added an Inst protocol which is implemented for java.util.Date and java.time.Instant by default. If you’re stuck on Joda-Time, you can extend the org.joda.time.ReadableInstant, which includes both Instant and DateTime using the following:

+
(jt/when-joda-time-loaded
+  (extend-type org.joda.time.ReadableInstant
+    Inst (inst-ms* [inst] (.getMillis inst))))
+
+

This snippet isn’t included in the Clojure.Java-Time code by default as both the Inst protocol and the Joda-Time types are external to the library.

+

Clocks

+

Java Time introduced a concept of Clock - a time entity which can seed the dates, times and zones. However, there’s no built-in facility which would allow you to influence the date-times created using default constructors à la Joda’s DateTimeUtils/setCurrentMillisSystem. Clojure.Java-Time tries to fix that with the with-clock macro and the corresponding with-clock-fn function:

+
(jt/zone-id)
+;=> #<java.time.ZoneRegion Europe/London>
 
-(offset-time (org.joda.time.DateTime/now))
-=> #<java.time.OffsetTime 22:00:00.000000000-00:00>
+(jt/with-clock (jt/system-clock "UTC")
+  (jt/zone-id))
+;=> #<java.time.ZoneRegion UTC>
 
-

Clocks

-

Java Time introduced a concept of Clock - a time entity which can seed the dates, times and zones. However, there’s no built-in facility which would allow you to influence the date-times create using default constructors ala Joda’s DateTimeUtils/setCurrentMillisSystem. Clojure.Java-Time tries to fix that with the with-clock macro and the corresponding with-clock-fn function:

-
(zone-id)
-=> #<java.time.ZoneRegion Europe/London>
+

In addition to the built-in java.time clocks, we provide a Mock clock which can be very handy in testing:

+
(def clock (jt/mock-clock 0 "UTC"))
+;=> #'user/clock
+
+(jt/with-clock clock
+  (jt/instant))
+;=> #object[java.time.Instant "1970-01-01T00:00:00Z"]
+
+(jt/advance-clock! clock (jt/plus (jt/hours 5) (jt/minutes 20)))
+;=> nil
+
+(jt/with-clock clock
+  (jt/instant))
+;=> #object[java.time.Instant "1970-01-01T05:20:00Z"]
+
+(jt/set-clock! clock 0)
+;=> nil
 
-(with-clock (system-clock "UTC")
-  (zone-id))
-=> #<java.time.ZoneRegion UTC>
+(jt/with-clock clock
+  (jt/instant))
+;=> #object[java.time.Instant "1970-01-01T00:00:00Z"]
 

Clock overrides works for all of the date-time types.

-

Fields, Units and Properties

+

Fields, Units and Properties

Date-Time entities are composed of date fields, while Duration entities are composed of time units. You can see all of the predefined fields and units via the java-time.repl ns:

-
(java-time.repl/show-fields)
-=> (:aligned-day-of-week-in-month
-    :aligned-day-of-week-in-year
-    :aligned-week-of-month
-    :aligned-week-of-year
-    :am-pm-of-day
-    :clock-hour-of-am-pm
-    ...)
-
-
(java-time.repl/show-units)
-=> (:centuries
-    :days
-    :decades
-    :eras
-    :forever
-    :half-days
-    ...)
+
(java-time.repl/show-fields)
+;=> (:aligned-day-of-week-in-month
+;    :aligned-day-of-week-in-year
+;    :aligned-week-of-month
+;    :aligned-week-of-year
+;    :am-pm-of-day
+;    :clock-hour-of-am-pm
+;    ...)
+
+
(java-time.repl/show-units)
+;=> (:centuries
+;    :days
+;    :decades
+;    :eras
+;    :forever
+;    :half-days
+;    ...)
 

You can obtain any field/unit like this:

-
(field :year)
-=> #object[java.time.temporal.ChronoField "Year"]
+
(jt/field :year)
+;=> #object[java.time.temporal.ChronoField "Year"]
 
-(unit :days)
-=> #object[java.time.temporal.ChronoUnit "Days"]
+(jt/unit :days)
+;=> #object[java.time.temporal.ChronoUnit "Days"]
 
-(field (local-date 2015) :year)
-=> #object[java.time.temporal.ChronoField "Year"]
+(jt/field (jt/local-date 2015) :year)
+;=> #object[java.time.temporal.ChronoField "Year"]
 

You can obtain all of the fields/units of the temporal entity:

-
(fields (local-date))
-=> {:proleptic-month #object[java.time.temporal.ChronoField ...}
+
(jt/fields (jt/local-date))
+;=> {:proleptic-month #object[java.time.temporal.ChronoField ...}
 
-(units (duration))
-=> {:seconds #object[java.time.temporal.ChronoUnit "Seconds"],
-    :nanos #object[java.time.temporal.ChronoUnit "Nanos"]}
+(jt/units (jt/duration))
+;=> {:seconds #object[java.time.temporal.ChronoUnit "Seconds"],
+;    :nanos #object[java.time.temporal.ChronoUnit "Nanos"]}
 

By themselves the fields and units aren’t very interesting. You can get the range of valid values for a field and a duration between two dates, but that’s about it:

-
(range (field :year))
-=> #object[java.time.temporal.ValueRange "-999999999 - 999999999"]
+
(jt/range (jt/field :year))
+;=> #object[java.time.temporal.ValueRange "-999999999 - 999999999"]
 
-(range (field :day-of-month))
-=> #object[java.time.temporal.ValueRange "1 - 28/31"]
+(jt/range (jt/field :day-of-month))
+;=> #object[java.time.temporal.ValueRange "1 - 28/31"]
 
-(time-between (local-date 2015 9) (local-date 2015 9 28) :days)
-=> 27
+(jt/time-between (jt/local-date 2015 9) (jt/local-date 2015 9 28) :days)
+;=> 27
 

Fields and units become interesting in conjunction with properties. Java-Time doesn’t support the concept of properties which is present in Joda-Time. There are reasons for that which I feel are only valid in a statically-typed API like Java’s. In Clojure, properties allow expressing time entity modifications and queries uniformly across all of the entity types.

-
(def prop (property (local-date 2015 2 28) :day-of-month))
-=> #java_time.temporal.TemporalFieldProperty{...}
+
(def prop (jt/property (jt/local-date 2015 2 28) :day-of-month))
+;=> #java_time.temporal.TemporalFieldProperty{...}
 
-(value prop)
-=> 28
+(jt/value prop)
+;=> 28
 
-(with-min-value prop)
-=> #object[java.time.LocalDate "2015-02-01"]
+(jt/with-min-value prop)
+;=> #object[java.time.LocalDate "2015-02-01"]
 
-(with-value prop 20)
-=> #object[java.time.LocalDate "2015-02-20"]
+(jt/with-value prop 20)
+;=> #object[java.time.LocalDate "2015-02-20"]
 
-(with-max-value prop)
-=> #object[java.time.LocalDate "2015-02-28"]
+(jt/with-max-value prop)
+;=> #object[java.time.LocalDate "2015-02-28"]
 
-(properties (local-date 2015 9 28))
-=> {:proleptic-month #java_time.temporal.TemporalFieldProperty{...}, ...}
+(jt/properties (jt/local-date 2015 9 28))
+;=> {:proleptic-month #java_time.temporal.TemporalFieldProperty{...}, ...}
 
-

Implementation Details

+

Implementation Details

Most of the temporal entity constructors with arities 1 to 3 use the conversion graph underneath. This provides for a very flexible way of defining the conversions while avoiding huge conditional statements and multiple definitions of the identical conversion logic. However, the flexibility comes with a cost:

    -
  1. The first call to a constructor will take a long time as it will try to find a path in the conversion graph. Subsequent calls will reuse the path.
  2. -
  3. It’s not trivial to evaluate the impact of adding and removing conversions both on the performance and the conversion path chosen for certain arguments.
  4. -
  5. You might get nonsensical results for some of the paths in the graph that you might expect would make sense.
  6. +
  7. The first call to a constructor will take a long time as it will try to find a path in the conversion graph. Subsequent calls will reuse the path.
  8. +
  9. It’s not trivial to evaluate the impact of adding and removing conversions both on the performance and the conversion path chosen for certain arguments.
  10. +
  11. You might get nonsensical results for some of the paths in the graph that you might expect would make sense.

Hopefully, the performance issue will be resolved in the future…

You can play with the conversion graph using the following helpers:

-
(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)
-=> {:cost 2.0,
-    :path [[#<java_time.graph.Types@15e43c24 [org.joda.time.DateTime]>
-            #<java_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]>]
-           [#<java_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]>
-            #<java_time.graph.Types@5360f6ae [java.time.OffsetTime]>]]}
+
(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)
+;=> {:cost 2.0,
+;    :path [[#<java_time.graph.Types@15e43c24 [org.joda.time.DateTime]>
+;            #<java_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]>]
+;           [#<java_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]>
+;            #<java_time.graph.Types@5360f6ae [java.time.OffsetTime]>]]}
 
 (java-time.repl/show-graph)
-=> {1
-     {org.threeten.extra.DayOfYear
-      [[#object[java_time.graph.Types "[java.lang.Number]"]
-        #object[java_time.graph.Conversion "Cost:1.0"]]],
-      java.lang.Number
-      [[#object[java_time.graph.Types "[java.time.Instant]"]
-        #object[java_time.graph.Conversion "Cost:1.0"]]
-        ...
-
\ No newline at end of file +;=> {1 +; {org.threeten.extra.DayOfYear +; [[#object[java_time.graph.Types "[java.lang.Number]"] +; #object[java_time.graph.Conversion "Cost:1.0"]]], +; java.lang.Number +; [[#object[java_time.graph.Types "[java.time.Instant]"] +; #object[java_time.graph.Conversion "Cost:1.0"]] +; ...}} + +
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 4666415..498a9d4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,3 +1,4 @@ -Clojure.java-time 0.3.0

Clojure.java-time 0.3.0

Released under the MIT License

Clojure wrapper for Java 8 Time API.

Installation

To install, add the following dependency to your project or build file:

[clojure.java-time "0.3.0"]

Topics

Namespaces

\ No newline at end of file +Clojure.java-time 1.4.3

Clojure.java-time 1.4.3

Released under the MIT License

Clojure wrapper for Java 8 Time API.

Installation

To install, add the following dependency to your project or build file:

[clojure.java-time "1.4.3"]

Topics

Namespaces

java-time

This namespace has been deprecated due to #91. Please migrate to java-time.api

+

Public variables and functions:

java-time.api

Public variables and functions:

\ No newline at end of file diff --git a/docs/java-time.api.html b/docs/java-time.api.html new file mode 100644 index 0000000..31e0876 --- /dev/null +++ b/docs/java-time.api.html @@ -0,0 +1,556 @@ + +java-time.api documentation

java-time.api

*

(* o v)

Entity o multiplied by the value v

+

+

(+ o & os)

Adds all of the os to the time entity o. + is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+
(j/+ (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2016-01-01">
+
+

-

(- o & os)

Subtracts all of the os from the time entity o

+
(j/- (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2014-01-01">
+
+

<

(< x)(< x y)(< x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <), otherwise false.

+
(j/< (local-date 2009) (local-date 2010) (local-date 2011))
+=> true
+
+(j/< (interval (instant 10000) (instant 1000000))
+     (instant 99999999))
+=> true
+
+

<=

(<= x)(<= x y)(<= x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <=), otherwise false.

+
(j/<= (local-date 2009) (local-date 2010) (local-date 2011))
+;=> true
+
+(j/<= (interval (instant 10000) (instant 1000000))
+      (instant 99999999))
+;=> true
+
+

=

(= x)(= x y)(= x y & more)

Returns true if all time entities represent the same time, otherwise false.

+

j/= is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+

e.g., (j/= (j/day-of-week :thursday) :thursday) => true

+

>

(> x)(> x y)(> x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >), otherwise false.

+
(j/> (local-date 2011) (local-date 2010) (local-date 2009))
+=> true
+
+(j/> (instant 99999999)
+     (interval (instant 10000) (instant 1000000)))
+=> true
+
+

>=

(>= x)(>= x y)(>= x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >=), otherwise false.

+
(j/>= (local-date 2011) (local-date 2010) (local-date 2009))
+;=> true
+
+(j/>= (instant 99999999)
+      (interval (instant 10000) (instant 1000000)))
+;=> true
+
+

abs

(abs a)

Returns the absolute value of a temporal amount:

+

(abs (negate x)) == (abs x)

+

abuts?

(abuts? i oi)

True if this interval abut with the other one

+

adjust

(adjust entity adjuster & args)

Adjusts the temporal entity using the provided adjuster with optional args.

+

The adjuster should either be a keyword which resolves to one of the predefined adjusters (see java-time.repl/show-adjusters) an instance of TemporalAdjuster or a function which returns another temporal entity when applied to the given one:

+
(adjust (local-date 2015 1 1) :next-working-day)
+=> #<LocalDate 2015-1-2>
+
+(adjust (local-date 2015 1 1) :first-in-month :monday)
+=> #<LocalDate 2015-1-5>
+
+(adjust (local-date 2015 1 1) plus (days 1))
+=> #<LocalDate 2015-1-2>
+
+

advance-clock!

(advance-clock! clock amount)

Advances the clock by the given time amount.

+

This mutates the mock clock.

+

after?

(after? x)(after? x y)(after? x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >), otherwise false.

+
(after? (local-date 2011) (local-date 2010) (local-date 2009))
+=> true
+
+(after? (instant 99999999)
+        (interval (instant 10000) (instant 1000000)))
+=> true
+
+

am-pm

(am-pm)(am-pm v)(am-pm fmt arg)

Returns the AmPm for the given keyword name (:am or :pm), ordinal or entity. Current AM/PM if no arguments given.

+

am-pm?

(am-pm? o)

True if org.threeten.extra.AmPm.

+

as

(as o k)(as o k1 k2)(as o k1 k2 & ks)

Values of property/unit identified by keys/objects ks of the temporal entity o, e.g.

+
(as (duration 1 :hours) :minutes)
+=> 60
+
+(as (local-date 2015 9) :year :month-of-year)
+=> [2015 9]
+
+

as-map

(as-map e)(as-map e value-fn)

Converts a time entity to a map of property key -> value as defined by the passed in value-fn. By default the actual value of the unit/field is produced.

+
(as-map (duration))
+=> {:nanos 0, :seconds 0}
+
+(as-map (local-date 2015 1 1))
+=> {:year 2015, :month-of-year 1, :day-of-month 1, ...}
+
+

available-zone-ids

(available-zone-ids)

Returns a set of string identifiers for all available ZoneIds.

+

before?

(before? x)(before? x y)(before? x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <), otherwise false.

+
(before? (local-date 2009) (local-date 2010) (local-date 2011))
+=> true
+
+(before? (interval (instant 10000) (instant 1000000))
+         (instant 99999999))
+=> true
+
+

chronology

(chronology o)

The Chronology of the entity

+

clock?

(clock? x)

Returns true if x is an instance of java.time.Clock.

+

contains?

(contains? i o)

True if the interval contains the given instant or interval

+

convert-amount

(convert-amount amount from-unit to-unit)

Converts an amount from one unit to another. Returns a map of:

+
    +
  • :whole - the whole part of the conversion in the to unit
  • +
  • :remainder - the remainder in the from unit
  • +
+

Arguments may be keywords or instances of TemporalUnit.

+

Converts between precise units–nanos up to weeks—treating days as exact multiples of 24 hours. Also converts between imprecise units—months up to millennia. See ChronoUnit and IsoFields for all of the supported units. Does not convert between precise and imprecise units.

+

Throws ArithmeticException if long overflow occurs during computation.

+
(convert-amount 10000 :seconds :hours)
+=> {:remainder 2800 :whole 2}
+
+

day-of-month

(day-of-month)(day-of-month arg)(day-of-month fmt arg)

Returns the DayOfMonth for the given entity, clock, zone or day of month. Current day of month if no arguments given.

+

day-of-month?

(day-of-month? o)

Returns true if o is org.threeten.extra.DayOfMonth, otherwise false.

+

day-of-week

(day-of-week)(day-of-week v)(day-of-week fmt arg)

Returns the DayOfWeek for the given day keyword name (e.g. :monday), ordinal or entity. Current day if no arguments given.

+

day-of-week?

(day-of-week? o)

True if java.time.DayOfWeek.

+

day-of-year

(day-of-year)(day-of-year arg)(day-of-year fmt arg)

Returns the DayOfYear for the given entity, clock, zone or day of year. Current day of year if no arguments given.

+

day-of-year?

(day-of-year? o)

Returns true if o is org.threeten.extra.DayOfYear, otherwise false.

+

days

(days i)

Returns a Period of i days.

+

duration

(duration)(duration arg0)(duration arg0 arg1)

Creates a duration - a temporal entity representing standard days, hours, minutes, millis, micros and nanos. The duration itself contains only seconds and nanos as properties.

+

Given one argument will:

+
    +
  • interpret as millis if a number
  • +
  • try to parse from the standard format if a string
  • +
  • extract supported units from another TemporalAmount
  • +
  • convert from a Joda Period/Duration
  • +
+

Given two arguments will:

+
    +
  • get a duration between two Temporals
  • +
  • get a duration of a specified unit, e.g. (duration 100 :seconds)
  • +
+

duration?

(duration? v)

Returns true if v is an instance of java.time.Duration, otherwise false.

+

end

(end i)

Gets the end instant of the interval

+

field

(field k)(field entity k)

Returns a TemporalField for the given key k or extracts the field from the given temporal entity.

+

You can see predefined fields via java-time.repl/show-fields.

+

If you want to make your own custom TemporalFields resolvable, you need to rebind the java-time.properties/*fields* to a custom java_time.properties.FieldGroup.

+

field?

(field? o)

True if this is a TemporalField.

+

fields

(fields o)

Fields present in this temporal entity

+

fixed-clock

(fixed-clock)(fixed-clock i)(fixed-clock i z)

Creates a fixed clock either at the current instant or at the supplied instant/instant + zone.

+

format

(format o)(format fmt o)

Formats the given time entity as a string.

+

Accepts something that can be converted to a DateTimeFormatter or a formatter key, e.g. :iso-offset-time, as a first argument. Given one argument uses the default format.

+
(format (zoned-date-time))
+=> "2015-03-21T09:22:46.677800+01:00[Europe/London]"
+
+(format :iso-date (zoned-date-time))
+"2015-03-21+01:00"
+
+

formatter

(formatter fmt)(formatter fmt arg1)

Constructs a DateTimeFormatter out of a

+
    +
  • format string - “yyyy/MM/dd”, “HH:mm”, etc.
  • +
  • formatter name - :iso-date, :iso-time, etc.
  • +
+

Accepts a map of options as an optional second argument:

+
    +
  • resolver-style - either :strict, :smart or :lenient
  • +
  • case - either :insensitive or :sensitive (defaults to :sensitive)
  • +
+

friday?

(friday? i)

Returns true if the given time entity with the day-of-week property falls on a Friday, otherwise false.

+

gap

(gap i oi)

Gets the gap between this interval and the other one or nil

+

hours

(hours i)

Returns a Duration of i hours.

+

instant

(instant)(instant arg0)(instant arg0 arg1)

Creates an Instant. The following arguments are supported:

+
    +
  • no arguments - current instant
  • +
  • one argument +
      +
    • clock
    • +
    • java.util.Date/Calendar
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • millis from epoch
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    +
  • +
+

instant->sql-timestamp

(instant->sql-timestamp instant-or-millis)

Creates a java.sql.Timestamp from the provided instant-or-millis - a millisecond numeric time value or something convertible to an Instant.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Timestamp if your drivers support them.

+

java.sql.Timestamp is a version of a java.util.Date supposed to be used as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types.

+

instant?

(instant? v)

Returns true if v is an instance of java.time.Instant, otherwise false.

+

interval

(interval o)(interval a b)

Constructs an interval out of a string, start and end instants or a start + duration:

+
(j/interval "2010-01-01T00:00:00Z/2013-01-01T00:00:00Z")
+=> #<Interval 2010-01-01T00:00:00Z/2013-01-01T00:00:00Z>
+
+(j/interval (j/instant 100000) (j/instant 1000000))
+=> #<Interval 1970-01-01T00:01:40Z/1970-01-01T00:16:40Z>
+
+(j/interval (j/instant 100000) (j/duration 15 :minutes))
+=> #<Interval 1970-01-01T00:01:40Z/1970-01-01T00:16:40Z>
+
+

Requires the optional threeten-extra dependency.

+

interval?

(interval? o)

True if Interval

+

iterate

(iterate f initial v & vs)

Returns a lazy sequence of initial , (apply f initial v vs), etc.

+

Useful when you want to produce a sequence of temporal entities, for example:

+
(iterate plus (days 0) 1)
+=> (#<Period P0D> #<Period P1D> #<Period P2D> ...)
+
+(iterate plus (local-date 2010 1 1) (years 1))
+=> (#<LocalDate 2010-01-01> #<LocalDate 2011-01-01> ...)
+
+(iterate adjust (local-date 2010 1 1) :next-working-day)
+=> (#<LocalDate 2010-01-01> #<LocalDate 2010-01-04> ...)
+
+

java-date

(java-date)(java-date a)(java-date a b)

Creates a java.util.Date out of any combination of arguments valid for instant or the Instant itself.

+

A java.util.Date represents an instant in time. It’s a direct analog of the java.time.Instant type introduced in the JSR-310. Please consider using the java.time.Instant (through instant) directly.

+

largest-min-value

(largest-min-value p)

Largest minimum value of this property

+

leap?

(leap? o)

True if the year of this entity is a leap year.

+

local-date

(local-date)(local-date arg0)(local-date arg0 arg1)(local-date arg0 arg1 arg2)

Creates a LocalDate. The following arguments are supported:

+
    +
  • no arguments - current local-date
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • an instant and a zone id
    • +
    • another temporal entity and an offset (preserves local time)
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • year, month and date
    • +
    +
  • +
+

local-date-time

(local-date-time)(local-date-time y m d h)(local-date-time y m d h mm)(local-date-time y m d h mm ss)(local-date-time y m d h mm ss n)(local-date-time arg0)(local-date-time arg0 arg1)(local-date-time arg0 arg1 arg2)

Creates a LocalDateTime. The following arguments are supported:

+
    +
  • no arguments - current local date-time
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • local date and local time
    • +
    • an instant and a zone id
    • +
    • formatter (format) and a string
    • +
    • year and month
    • +
    +
  • +
  • +

    three and more arguments - year/month/day/…

    +
  • +
+

local-date-time?

(local-date-time? v)

Returns true if v is an instance of java.time.LocalDateTime, otherwise false.

+

local-date?

(local-date? v)

Returns true if v is an instance of java.time.LocalDate, otherwise false.

+

local-time

(local-time)(local-time h m s nn)(local-time arg0)(local-time arg0 arg1)(local-time arg0 arg1 arg2)

Creates a LocalTime. The following arguments are supported:

+
    +
  • no arguments - current local time
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • hours
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • an instant and a zone id
    • +
    • hours and minutes
    • +
    +
  • +
  • three/four arguments - hour, minute, second, nanos
  • +
+

local-time?

(local-time? v)

Returns true if v is an instance of java.time.LocalTime, otherwise false.

+

max

(max o & os)

Latest/longest of the given time entities. Entities should be of the same type

+

max-value

(max-value p)

Maximum value of this property, e.g. 29th of February for months

+

micros

(micros micros)

Duration of a specified number of microseconds.

+

millis

(millis i)

Returns a Duration of i millis.

+

min

(min o & os)

Earliest/shortest of the given time entities. Entities should be of the same type

+

min-value

(min-value p)

Minimum value of this property

+

minus

(minus o & os)

Subtracts all of the os from the time entity o

+
(j/minus (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2014-01-01">
+
+

minutes

(minutes i)

Returns a Duration of i minutes.

+

mock-clock

(mock-clock)(mock-clock instant)(mock-clock instant zone)

Returns a mock implementation of the java.time.Clock. The mock supports advance-clock! operation which allows to move the time in the clock, e.g.:

+
(let [clock (mock-clock 0 "UTC")]
+  (with-clock clock
+    (is (= (value clock) 0))
+    (is (= (instant) (instant 0)))
+    (advance-clock! clock (j/millis 1))
+    (is (= (value clock) 1))
+    (is (= (instant) (instant 1)))))
+
+

You can move the clock back via advancing by a negative temporal amount.

+

Creates a clock at epoch in the default time zone when called without arguments.

+

monday?

(monday? i)

Returns true if the given time entity with the day-of-week property falls on a Monday, otherwise false.

+

month

(month)(month v)(month fmt arg)

Returns the Month for the given month keyword name (e.g. :january), ordinal or entity. Current month if no arguments given.

+

month-day

(month-day)(month-day arg)(month-day a b)

Returns the MonthDay for the given entity, string, clock, zone or month/day combination. Current month-day if no arguments given.

+

month-day?

(month-day? o)

Returns true if o is java.time.MonthDay, otherwise false.

+

month?

(month? o)

True if java.time.Month.

+

months

(months i)

Returns a Period of i months.

+

move-end-by

(move-end-by i & os)

Moves the end instant of the interval by the sum of given periods/durations/numbers of milliseconds.

+
(move-start-by (interval 0 10000) (millis 1000) (seconds 1))
+=> #<Interval ...:00Z/...:12Z>
+
+

Fails if the new end instant falls before the start instant.

+
(move-end-by (interval 0 10000) (millis -11000))
+=> DateTimeException...
+
+

move-end-to

(move-end-to i new-end)

Moves the end of the interval to the given instant (or something convertible to an instant):

+
(move-end-to (interval 0 10000) (instant 15000))
+=> #<Interval ...:00Z/...:15Z>
+
+

Fails if the new end instant falls before the start instant:

+
(move-end-to (interval 0 10000) (millis -1))
+=> DateTimeException...
+
+

move-start-by

(move-start-by i & os)

Moves the start instant of the interval by the sum of given periods/durations/numbers of milliseconds:

+
(move-start-by (interval 0 10000) (millis 1000) (seconds 1))
+=> #<Interval ...:02Z/...:10Z>
+
+

Fails if the new start instant falls after the end instant.

+
(move-start-by (interval 0 10000) (millis 11000))
+;=> DateTimeException...
+
+

move-start-to

(move-start-to i new-start)

Moves the start instant of the interval to the given instant (or something convertible to an instant):

+
(move-start-to (interval 0 10000) (instant 5000))
+=> #<Interval ...:05Z/...:10Z>
+
+

Fails if the new start instant falls after the end instant:

+
(move-start-to (interval 0 10000) (millis 15000))
+=> DateTimeException...
+
+

multiply-by

(multiply-by o v)

Entity o multiplied by the value v

+

nanos

(nanos i)

Returns a Duration of i nanos.

+

negate

(negate a)

Negates a temporal amount:

+

(negate (negate x)) == x

+

negative?

(negative? a)

True if the amount is negative

+

not-after?

(not-after? x)(not-after? x y)(not-after? x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <=), otherwise false.

+
(not-after? (local-date 2009) (local-date 2010) (local-date 2011))
+;=> true
+
+(not-after? (interval (instant 10000) (instant 1000000))
+            (instant 99999999))
+;=> true
+
+

not-before?

(not-before? x)(not-before? x y)(not-before? x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >=), otherwise false.

+
(not-before? (local-date 2011) (local-date 2010) (local-date 2009))
+;=> true
+
+(not-before? (instant 99999999)
+             (interval (instant 10000) (instant 1000000)))
+;=> true
+
+

offset-clock

(offset-clock d)(offset-clock c d)

Creates a clock offset from the current/provided clock by a given duration.

+

offset-date-time

(offset-date-time)(offset-date-time y m d h)(offset-date-time y mo d h m)(offset-date-time y mo d h m s)(offset-date-time y mo d h m s n)(offset-date-time y mo d h m s n o)(offset-date-time arg0)(offset-date-time arg0 arg1)(offset-date-time arg0 arg1 arg2)

Creates an OffsetDateTime. The following arguments are supported:

+
    +
  • no arguments - current date-time with the default offset
  • +
  • one argument +
      +
    • clock
    • +
    • zone offset
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • local date-time and an offset
    • +
    • another temporal entity and an offset (preserves local time)
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • local date, local time and an offset
    • +
    • year, month and date
    • +
    +
  • +
  • four up to seven arguments - position date-time constructors
  • +
  • eight arguments - time fields up to nanoseconds and a zone offset
  • +
+

If zone offset is not specified, default will be used. You can check the default offset by invoking (zone-offset).

+

offset-date-time?

(offset-date-time? v)

Returns true if v is an instance of java.time.OffsetDateTime, otherwise false.

+

offset-time

(offset-time)(offset-time h m s)(offset-time h m s n)(offset-time h m s n o)(offset-time arg0)(offset-time arg0 arg1)

Creates an OffsetTime. The following arguments are supported:

+
    +
  • no arguments - current time with the default offset
  • +
  • one argument +
      +
    • clock
    • +
    • zone id
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • hour
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • local time and an offset
    • +
    • instant and an offset
    • +
    • hour and minutes
    • +
    +
  • +
  • three arguments - hours, minutes, seconds
  • +
  • four arguments - hours, minutes, seconds, nanos
  • +
  • five arguments - last is the offset
  • +
+

If zone offset is not specified, default will be used. You can check the default offset by invoking (zone-offset).

+

offset-time?

(offset-time? v)

Returns true if v is an instance of java.time.OffsetTime, otherwise false.

+

overlap

(overlap i oi)

Gets the overlap between this interval and the other one or nil

+

overlaps?

(overlaps? i oi)

True if this interval overlaps the other one

+

period

(period)(period arg0)(period arg0 arg1)(period arg0 arg1 arg2)

Creates a period - a temporal entity consisting of years, months and days.

+

Given one argument will

+
    +
  • interpret as years if a number
  • +
  • try to parse from the standard format if a string
  • +
  • extract supported units from another TemporalAmount
  • +
  • convert from a Joda Period
  • +
+

Given two arguments will

+
    +
  • get a period of a specified unit, e.g. (period 10 :months)
  • +
  • get a period between two temporals by converting them to local dates
  • +
  • get a period of a specified number of years and months
  • +
+

Given three arguments will create a year/month/day period.

+

period?

(period? v)

Returns true if v is an instance of java.time.Period, otherwise false.

+

plus

(plus o & os)

Adds all of the os to the time entity o. plus is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+
(j/plus (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2016-01-01">
+
+

properties

(properties o)

Map of properties present in this temporal entity

+

property

(property o k)

Property of this temporal entity under key k

+

quarter

(quarter)(quarter v)(quarter fmt arg)

Returns the Quarter for the given quarter keyword name (e.g. :q1), ordinal or entity. Current quarter if no arguments given.

+

quarter?

(quarter? o)

True if org.threeten.extra.Quarter.

+

range

(range p)

Range of values for this property

+

saturday?

(saturday? i)

Returns true if the given time entity with the day-of-week property falls on a Saturday, otherwise false.

+

seconds

(seconds i)

Returns a Duration of i seconds.

+

set-clock!

(set-clock! clock time)

Sets the clock to the given time.

+

This mutates the mock clock.

+

smallest-max-value

(smallest-max-value p)

Smallest maximum value of this property, e.g. 28th of February for months

+

sql-date

(sql-date)(sql-date arg0)(sql-date arg0 arg1)(sql-date arg0 arg1 arg2)

Creates a java.sql.Date out of any combination of arguments valid for local-date or the LocalDate itself.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Date if your drivers support them.

+

Even though java.sql.Date extends a java.util.Date, it’s supposed to be used as a local date (no time component or time zone) for the purposes of conversion from/to native JDBC driver DATE types.

+

sql-time

(sql-time)(sql-time arg0)(sql-time arg0 arg1)(sql-time arg0 arg1 arg2)

Creates a java.sql.Time out of any combination of arguments valid for local-time (except the nanos constructor) or the LocalTime itself.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Time if your drivers support them.

+

Even though java.sql.Time extends a java.util.Date, it’s supposed to be used as a local time (no date component or time zone) for the purposes of conversion from/to native JDBC driver TIME types.

+

sql-timestamp

(sql-timestamp)(sql-timestamp arg0)(sql-timestamp arg0 arg1)(sql-timestamp arg0 arg1 arg2)(sql-timestamp arg0 arg1 arg2 arg3)(sql-timestamp arg0 arg1 arg2 arg3 arg4)(sql-timestamp arg0 arg1 arg2 arg3 arg4 arg5)(sql-timestamp arg0 arg1 arg2 arg3 arg4 arg5 arg6)

Creates a java.sql.Timestamp in the local time zone out of any combination of arguments valid for local-date-time or the LocalDateTime itself.

+

Does not support Timestamp construction from an Instant or a long millis value—please use instant->sql-timestamp for this purpose.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Timestamp if your drivers support them.

+

java.sql.Timestamp is a version of a java.util.Date supposed to be used as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types.

+

standard-days

(standard-days i)

Returns a Duration of i days.

+

start

(start i)

Gets the start instant of the interval

+

sunday?

(sunday? i)

Returns true if the given time entity with the day-of-week property falls on a Sunday, otherwise false.

+

supports?

(supports? o p)

True if the o entity supports the p property

+

system-clock

(system-clock)(system-clock k)

Creates a system clock. In the default time zone if called without arguments, otherwise accepts a Zone Id.

+

thursday?

(thursday? i)

Returns true if the given time entity with the day-of-week property falls on a Thursday, otherwise false.

+

tick-clock

(tick-clock d)(tick-clock c d)

Creates a clock wrapping system/provided clock that only ticks as per specified duration.

+

time-between

(time-between o e u)

Time between temporal entities o and e in unit u.

+
(j/time-between (j/local-date 2015) (j/local-date 2016) :days)
+=> 365
+
+(j/time-between :days (j/local-date 2015) (j/local-date 2016))
+=> 365
+
+

to-java-date

deprecated

(to-java-date o)

Converts a date entity to a java.util.Date.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.Instant. Please consider using java-date instead.

+

to-millis-from-epoch

(to-millis-from-epoch o)

Converts a date entity to a long representing the number of milliseconds from epoch.

+

to-sql-date

deprecated

(to-sql-date o)

Converts a local date entity to a java.sql.Date.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.LocalDate. Please consider using sql-date instead.

+

to-sql-timestamp

deprecated

(to-sql-timestamp o)

Converts a date entity to a java.sql.Timestamp.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.Instant. Please consider using sql-timestamp instead.

+

truncate-to

(truncate-to o u)

Truncates this entity to the specified time unit. Only works for units that divide into the length of standard day without remainder (up to :days).

+

tuesday?

(tuesday? i)

Returns true if the given time entity with the day-of-week property falls on a Tuesday, otherwise false.

+

unit

(unit k)(unit entity k)

Returns a TemporalUnit for the given key k or extracts the field from the given temporal entity.

+

You can see predefined units via java-time.repl/show-units.

+

If you want to make your own custom TemporalUnits resolvable, you need to rebind the java-time.properties/*units* to a custom java_time.properties.UnitGroup.

+

unit?

(unit? o)

True if this is a TemporalUnit.

+

units

(units o)

Units present in this temporal entity.

+

value

(value p)

Value of the property

+

value-range

(value-range min max)(value-range arg0)

Creates a ValueRange given the min and max amounts or a map of :min-smallest, :max-smallest, :min-largest and :max-largest.

+

wednesday?

(wednesday? i)

Returns true if the given time entity with the day-of-week property falls on a Wednesday, otherwise false.

+

weekday?

(weekday? dt)

Complement of weekend?.

+

weekend?

(weekend? dt)

Returns true if argument is saturday? or sunday?, otherwise false.

+

weeks

(weeks i)

Returns a Period of i weeks.

+

when-joda-time-loaded

macro

(when-joda-time-loaded & body)

Execute the body when Joda-Time classes are found on the classpath.

+

Take care - when AOT-compiling code using this macro, the Joda-Time classes must be on the classpath at compile time!

+

with-clock

macro

(with-clock c & forms)

Executes the given forms in the scope of the provided clock.

+

All the temporal entities that get created without parameters will inherit their values from the clock:

+

(with-clock (system-clock “Europe/London”) (zone-id)) => #<java.time.ZoneRegion Europe/London>

+

with-clock-fn

(with-clock-fn c f)

Executes the given function in the scope of the provided clock. All the temporal entities that get created without parameters will inherit their values from the clock.

+

with-largest-min-value

(with-largest-min-value p)

Underlying temporal entity with the value set to the largest minimum available for this property

+

with-max-value

(with-max-value p)

Underlying temporal entity with the value set to the maximum available for this property

+

with-min-value

(with-min-value p)

Underlying temporal entity with the value set to the minimum available for this property

+

with-offset

(with-offset o offset)

Sets the offset to the specified value ensuring that the local time stays the same.

+

(offset-time 10 30 0 0 +2) => #<java.time.OffsetTime 10:30+02:00> (with-offset *1 +3) => #<java.time.OffsetTime 10:30+03:00>

+

with-offset-same-instant

(with-offset-same-instant o offset)

Sets the offset to the specified value ensuring that the result has the same instant, e.g.:

+

(offset-time 10 30 0 0 +2) => #<java.time.OffsetTime 10:30+02:00> (with-offset-same-instant *1 +3) => #<java.time.OffsetTime 11:30+03:00>

+

with-smallest-max-value

(with-smallest-max-value p)

Underlying temporal entity with the value set to the smallest maximum available for this property

+

with-value

(with-value p v)

Underlying temporal entity with the value of this property set to v

+

with-zone

(with-zone o z)

Returns this temporal entity with the specified ZoneId

+

with-zone-same-instant

(with-zone-same-instant zdt z)

Sets the zone to the specified value ensuring that the result has the same instant, e.g.:

+

(zoned-date-time 2015) => #<java.time.ZonedDateTime 2015-01-01T00:00+00:00Europe/London> (with-zone-same-instant *1 “America/New_York”) => #<java.time.ZonedDateTime 2014-12-31T18:00-05:00America/New_York>

+

year

(year)(year arg)(year fmt arg)

Returns the Year for the given entity, string, clock, zone or number. Current year if no arguments given.

+

year-month

(year-month)(year-month arg)(year-month a b)

Returns the YearMonth for the given entity, string, clock, zone or month/day combination. Current year-month if no arguments given.

+

year-month?

(year-month? o)

Returns true if o is java.time.YearMonth, otherwise false.

+

year-quarter

(year-quarter)(year-quarter arg)(year-quarter a b)

Returns the YearQuarter for the given entity, clock, zone or year with quarter. Current year quarter if no arguments given.

+

year-quarter?

(year-quarter? o)

Returns true if o is org.threeten.extra.YearQuarter, otherwise false.

+

year?

(year? o)

Returns true if o is java.time.Year, otherwise false.

+

years

(years i)

Returns a Period of i years.

+

zero?

(zero? a)

True if the amount is zero

+

zone-id

(zone-id)(zone-id arg0)(zone-id arg0 arg1)

Creates a ZoneId from a string identifier, java.util.TimeZone or extracts from another temporal entity.

+

Returns default system zone id if no arguments provided.

+

Given two arguments will use the second as the offset.

+

zone-id?

(zone-id? v)

Returns true if v is an instance of java.time.ZoneId, otherwise false.

+

zone-offset

(zone-offset)(zone-offset o)(zone-offset h m)(zone-offset h m s)

Creates a ZoneOffset from a string identifier (e.g. “+01”), a number of hours/hours and minutes/hours, minutes and seconds or extracts from another temporal entity.

+

Returns default system zone offset if no arguments provided.

+

zoned-date-time

(zoned-date-time)(zoned-date-time y m d h)(zoned-date-time y mo d h m)(zoned-date-time y mo d h m s)(zoned-date-time y mo d h m s n)(zoned-date-time y mo d h m s n o)(zoned-date-time arg0)(zoned-date-time arg0 arg1)(zoned-date-time arg0 arg1 arg2)

Creates a ZonedDateTime. The following arguments are supported:

+
    +
  • no arguments - current date-time in the default zone
  • +
  • one argument +
      +
    • clock
    • +
    • zone id
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter and a string
    • +
    • local date-time and a zone id
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • local date, local time and a zone id
    • +
    • year, month and day
    • +
    +
  • +
  • four to seven arguments - date-time fields
  • +
  • eight arguments - last is the zone id
  • +
+

If zone id is not specified, default zone id will be used. You can check the default zone by invoking (zone-id).

+

zoned-date-time?

(zoned-date-time? v)

Returns true if v is an instance of java.time.ZonedDateTime, otherwise false.

+
\ No newline at end of file diff --git a/docs/java-time.html b/docs/java-time.html index ec0f835..067087d 100644 --- a/docs/java-time.html +++ b/docs/java-time.html @@ -1,446 +1,562 @@ -java-time documentation

java-time

abs

(abs a)
Returns the absolute value of a temporal amount:
-
-(abs (negate x)) == (abs x)

abuts?

(abuts? i oi)
True if this interval abut with the other one
-

adjust

(adjust entity adjuster & args)
Adjusts the temporal `entity` using the provided `adjuster` with optional `args`.
-
-The adjuster should either be a keyword which resolves to one of the
-predefined adjusters (see `java-time.repl/show-adjusters`) an instance of
-`TemporalAdjuster` or a function which returns another temporal entity when
-applied to the given one:
-
-  (adjust (local-date 2015 1 1) :next-working-day)
-  => #<LocalDate 2015-1-2>
-
-  (adjust (local-date 2015 1 1) :first-in-month :monday)
-  => #<LocalDate 2015-1-5>
-
-  (adjust (local-date 2015 1 1) plus (days 1))
-  => #<LocalDate 2015-1-2>

after?

(after? x)(after? x y)(after? x y & more)
Returns non-nil if time entities are ordered from the earliest to the latest
-(same semantics as `>`):
-
-  (after? (local-date 2011) (local-date 2010) (local-date 2009))
-  => truthy...
-
-  (after? (instant 99999999)
-          (interval (instant 10000) (instant 1000000)))
-  => truthy...

am-pm

(am-pm)(am-pm v__8876__auto__)(am-pm fmt__8877__auto__ arg__8878__auto__)
Returns the `AmPm` for the given keyword name (`:am` or `:pm`),
-ordinal or entity. Current AM/PM if no arguments given.

am-pm?

(am-pm? o__8875__auto__)

as

(as o k)(as o k1 k2)(as o k1 k2 & ks)
Values of property/unit identified by keys/objects `ks` of the temporal
-entity `o`, e.g.
-
-  (as (duration 1 :hour) :minutes)
-  => 60
-
-  (as (local-date 2015 9) :year :month-of-year)
-  => [2015 9]

as-map

(as-map e)(as-map e value-fn)
Converts a time entity to a map of property key -> value as defined by the
-passed in `value-fn`. By default the actual value of the unit/field is
-produced.
-
-  (as-map (duration))
-  => {:nanos 0, :seconds 0}
-
-  (as-map (local-date 2015 1 1))
-  => {:year 2015, :month-of-year 1, :day-of-month 1, ...}

available-zone-ids

(available-zone-ids)

before?

(before? x)(before? x y)(before? x y & more)
Returns non-nil if time entities are ordered from the earliest to the latest
-(same semantics as `<`):
-
-  (before? (local-date 2009) (local-date 2010) (local-date 2011))
-  => truthy...
-
-  (before? (interval (instant 10000) (instant 1000000))
-           (instant 99999999))
-  => truthy...

chronology

(chronology o)
The `Chronology` of the entity
-

contains?

(contains? i o)
True if the interval contains the given instant or interval
-

convert-amount

(convert-amount amount from-unit to-unit)
Converts an amount from one unit to another. Returns a map of:
-  * `:whole` - the whole part of the conversion in the `to` unit
-  * `:remainder` - the remainder in the `from` unit
-
-Arguments may be keywords or instances of `TemporalUnit`.
-
-Converts between precise units - nanos up to weeks, treating days as exact
-multiples of 24 hours. Also converts between imprecise units - months up to
-millenia. See `ChronoUnit` and `IsoFields` for all of the supported units.
-Does not convert between precise and imprecise units.
-
-Throws `ArithmeticException` if long overflow occurs during computation.
-
-  (convert-amount 10000 :seconds :hours)
-  => {:remainder 2800 :whole 2}

day-of-month

(day-of-month)(day-of-month G__9071)(day-of-month fmt__8905__auto__ arg__8906__auto__)
Returns the `DayOfMonth` for the given entity, clock, zone or day of month.
-Current day of month if no arguments given.

day-of-month?

(day-of-month? o__8904__auto__)

day-of-week

(day-of-week)(day-of-week v__8876__auto__)(day-of-week fmt__8877__auto__ arg__8878__auto__)
Returns the `DayOfWeek` for the given day keyword name (e.g. `:monday`),
-ordinal or entity. Current day if no arguments given.

day-of-week?

(day-of-week? o__8875__auto__)

day-of-year

(day-of-year)(day-of-year G__9082)(day-of-year fmt__8905__auto__ arg__8906__auto__)
Returns the `DayOfYear` for the given entity, clock, zone or day of year.
-Current day of year if no arguments given.

day-of-year?

(day-of-year? o__8904__auto__)

days

(days v__8370__auto__)

duration

(duration)(duration arg_1_8331)(duration arg_1_8332 arg_2_8333)
Creates a duration - a temporal entity representing standard days, hours,
-minutes, millis, micros and nanos. The duration itself contains only seconds
-and nanos as properties.
-
-Given one argument will
-  * interpret as millis if a number
-  * try to parse from the standard format if a string
-  * extract supported units from another `TemporalAmount`
-  * convert from a Joda Period/Duration
-
-Given two arguments will
-  * get a duration between two `Temporal`s
-  * get a duration of a specified unit, e.g. `(duration 100 :seconds)`

duration?

(duration? v__7519__auto__)
True if an instance of Duration.
-

end

(end i)
Gets the end instant of the interval
-

field

(field k)(field entity k)
Returns a `TemporalField` for the given key `k` or extracts the field from
-the given temporal `entity`.
-
-You can see predefined fields via `java-time.repl/show-fields`.
-
-If you want to make your own custom TemporalFields resolvable, you need to rebind the
-`java-time.properties/*fields*` to a custom `java-time.properties.FieldGroup`.

field?

(field? o)
True if this is a `TemporalField`.
-

fields

(fields o)
Fields present in this temporal entity
-

fixed-clock

(fixed-clock)(fixed-clock i)(fixed-clock i z)
Creates a fixed clock either at the current instant or at the supplied
-instant/instant + zone.

format

(format o)(format fmt o)
Formats the given time entity as a string.
-
-Accepts something that can be converted to a `DateTimeFormatter` as a first
-argument. Given one argument uses the default format.

formatter

(formatter fmt)(formatter fmt {:keys [resolver-style]})
Constructs a DateTimeFormatter out of a
-
-* format string - "YYYY/mm/DD", "YYY HH:MM", etc.
-* formatter name - :iso-date, :iso-time, etc.
-   - More examples can be found here
-
-Accepts a map of options as an optional second argument:
-
-* `resolver-style` - either `:strict`, `:smart `or `:lenient`

friday?

(friday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a friday.

gap

(gap i oi)
Gets the gap between this interval and the other one or `nil`
-

hours

(hours v__8353__auto__)
Duration of a specified number of hours.
-

instant

(instant)(instant arg_1_8005)(instant arg_1_8006 arg_2_8007)
Creates an `Instant`. The following arguments are supported:
-
-* no arguments - current instant
-* one argument
-  + clock
-  + java.util.Date/Calendar
-  + another temporal entity
-  + string representation
-  + millis from epoch
-* two arguments
-  + formatter (format) and a string

instant?

(instant? v__7519__auto__)
True if an instance of Instant.
-

interval

(interval o)(interval a b)
Constructs an interval out of a string, start and end instants or a start
-+ duration:
-
-(j/interval "2010-01-01T00:00:00Z/2013-01-01T00:00:00Z")
+java-time documentation

java-time

deprecated in 1.1.0

This namespace has been deprecated due to #91. Please migrate to java-time.api

+

This namespace will continue to exist and be updated. For maximum JVM compatibility, please migrate to java-time.api, which provides the same interface. java-time and java-time.api and can be freely intermixed within the same library, so you can safely migrate your own code even if your dependencies use the old namespace.

+

Migration steps:

+
    +
  1. rename all references from java-time to java-time.api. eg., (:require [java-time :as jt]) => (:require [java-time.api :as jt])
  2. +
+

*

(* o v)

Entity o multiplied by the value v

+

+

(+ o & os)

Adds all of the os to the time entity o. + is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+
(j/+ (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2016-01-01">
+
+

-

(- o & os)

Subtracts all of the os from the time entity o

+
(j/- (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2014-01-01">
+
+

<

(< x)(< x y)(< x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <), otherwise false.

+
(j/< (local-date 2009) (local-date 2010) (local-date 2011))
+=> true
+
+(j/< (interval (instant 10000) (instant 1000000))
+     (instant 99999999))
+=> true
+
+

<=

(<= x)(<= x y)(<= x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <=), otherwise false.

+
(j/<= (local-date 2009) (local-date 2010) (local-date 2011))
+;=> true
+
+(j/<= (interval (instant 10000) (instant 1000000))
+      (instant 99999999))
+;=> true
+
+

=

(= x)(= x y)(= x y & more)

Returns true if all time entities represent the same time, otherwise false.

+

j/= is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+

e.g., (j/= (j/day-of-week :thursday) :thursday) => true

+

>

(> x)(> x y)(> x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >), otherwise false.

+
(j/> (local-date 2011) (local-date 2010) (local-date 2009))
+=> true
+
+(j/> (instant 99999999)
+     (interval (instant 10000) (instant 1000000)))
+=> true
+
+

>=

(>= x)(>= x y)(>= x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >=), otherwise false.

+
(j/>= (local-date 2011) (local-date 2010) (local-date 2009))
+;=> true
+
+(j/>= (instant 99999999)
+      (interval (instant 10000) (instant 1000000)))
+;=> true
+
+

abs

(abs a)

Returns the absolute value of a temporal amount:

+

(abs (negate x)) == (abs x)

+

abuts?

(abuts? i oi)

True if this interval abut with the other one

+

adjust

(adjust entity adjuster & args)

Adjusts the temporal entity using the provided adjuster with optional args.

+

The adjuster should either be a keyword which resolves to one of the predefined adjusters (see java-time.repl/show-adjusters) an instance of TemporalAdjuster or a function which returns another temporal entity when applied to the given one:

+
(adjust (local-date 2015 1 1) :next-working-day)
+=> #<LocalDate 2015-1-2>
+
+(adjust (local-date 2015 1 1) :first-in-month :monday)
+=> #<LocalDate 2015-1-5>
+
+(adjust (local-date 2015 1 1) plus (days 1))
+=> #<LocalDate 2015-1-2>
+
+

advance-clock!

(advance-clock! clock amount)

Advances the clock by the given time amount.

+

This mutates the mock clock.

+

after?

(after? x)(after? x y)(after? x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >), otherwise false.

+
(after? (local-date 2011) (local-date 2010) (local-date 2009))
+=> true
+
+(after? (instant 99999999)
+        (interval (instant 10000) (instant 1000000)))
+=> true
+
+

am-pm

(am-pm)(am-pm v)(am-pm fmt arg)

Returns the AmPm for the given keyword name (:am or :pm), ordinal or entity. Current AM/PM if no arguments given.

+

am-pm?

(am-pm? o)

True if org.threeten.extra.AmPm.

+

as

(as o k)(as o k1 k2)(as o k1 k2 & ks)

Values of property/unit identified by keys/objects ks of the temporal entity o, e.g.

+
(as (duration 1 :hours) :minutes)
+=> 60
+
+(as (local-date 2015 9) :year :month-of-year)
+=> [2015 9]
+
+

as-map

(as-map e)(as-map e value-fn)

Converts a time entity to a map of property key -> value as defined by the passed in value-fn. By default the actual value of the unit/field is produced.

+
(as-map (duration))
+=> {:nanos 0, :seconds 0}
+
+(as-map (local-date 2015 1 1))
+=> {:year 2015, :month-of-year 1, :day-of-month 1, ...}
+
+

available-zone-ids

(available-zone-ids)

Returns a set of string identifiers for all available ZoneIds.

+

before?

(before? x)(before? x y)(before? x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <), otherwise false.

+
(before? (local-date 2009) (local-date 2010) (local-date 2011))
+=> true
+
+(before? (interval (instant 10000) (instant 1000000))
+         (instant 99999999))
+=> true
+
+

chronology

(chronology o)

The Chronology of the entity

+

clock?

(clock? x)

Returns true if x is an instance of java.time.Clock.

+

contains?

(contains? i o)

True if the interval contains the given instant or interval

+

convert-amount

(convert-amount amount from-unit to-unit)

Converts an amount from one unit to another. Returns a map of:

+
    +
  • :whole - the whole part of the conversion in the to unit
  • +
  • :remainder - the remainder in the from unit
  • +
+

Arguments may be keywords or instances of TemporalUnit.

+

Converts between precise units–nanos up to weeks—treating days as exact multiples of 24 hours. Also converts between imprecise units—months up to millennia. See ChronoUnit and IsoFields for all of the supported units. Does not convert between precise and imprecise units.

+

Throws ArithmeticException if long overflow occurs during computation.

+
(convert-amount 10000 :seconds :hours)
+=> {:remainder 2800 :whole 2}
+
+

day-of-month

(day-of-month)(day-of-month arg)(day-of-month fmt arg)

Returns the DayOfMonth for the given entity, clock, zone or day of month. Current day of month if no arguments given.

+

day-of-month?

(day-of-month? o)

Returns true if o is org.threeten.extra.DayOfMonth, otherwise false.

+

day-of-week

(day-of-week)(day-of-week v)(day-of-week fmt arg)

Returns the DayOfWeek for the given day keyword name (e.g. :monday), ordinal or entity. Current day if no arguments given.

+

day-of-week?

(day-of-week? o)

True if java.time.DayOfWeek.

+

day-of-year

(day-of-year)(day-of-year arg)(day-of-year fmt arg)

Returns the DayOfYear for the given entity, clock, zone or day of year. Current day of year if no arguments given.

+

day-of-year?

(day-of-year? o)

Returns true if o is org.threeten.extra.DayOfYear, otherwise false.

+

days

(days i)

Returns a Period of i days.

+

duration

(duration)(duration arg0)(duration arg0 arg1)

Creates a duration - a temporal entity representing standard days, hours, minutes, millis, micros and nanos. The duration itself contains only seconds and nanos as properties.

+

Given one argument will:

+
    +
  • interpret as millis if a number
  • +
  • try to parse from the standard format if a string
  • +
  • extract supported units from another TemporalAmount
  • +
  • convert from a Joda Period/Duration
  • +
+

Given two arguments will:

+
    +
  • get a duration between two Temporals
  • +
  • get a duration of a specified unit, e.g. (duration 100 :seconds)
  • +
+

duration?

(duration? v)

Returns true if v is an instance of java.time.Duration, otherwise false.

+

end

(end i)

Gets the end instant of the interval

+

field

(field k)(field entity k)

Returns a TemporalField for the given key k or extracts the field from the given temporal entity.

+

You can see predefined fields via java-time.repl/show-fields.

+

If you want to make your own custom TemporalFields resolvable, you need to rebind the java-time.properties/*fields* to a custom java_time.properties.FieldGroup.

+

field?

(field? o)

True if this is a TemporalField.

+

fields

(fields o)

Fields present in this temporal entity

+

fixed-clock

(fixed-clock)(fixed-clock i)(fixed-clock i z)

Creates a fixed clock either at the current instant or at the supplied instant/instant + zone.

+

format

(format o)(format fmt o)

Formats the given time entity as a string.

+

Accepts something that can be converted to a DateTimeFormatter or a formatter key, e.g. :iso-offset-time, as a first argument. Given one argument uses the default format.

+
(format (zoned-date-time))
+=> "2015-03-21T09:22:46.677800+01:00[Europe/London]"
+
+(format :iso-date (zoned-date-time))
+"2015-03-21+01:00"
+
+

formatter

(formatter fmt)(formatter fmt arg1)

Constructs a DateTimeFormatter out of a

+
    +
  • format string - “yyyy/MM/dd”, “HH:mm”, etc.
  • +
  • formatter name - :iso-date, :iso-time, etc.
  • +
+

Accepts a map of options as an optional second argument:

+
    +
  • resolver-style - either :strict, :smart or :lenient
  • +
  • case - either :insensitive or :sensitive (defaults to :sensitive)
  • +
+

friday?

(friday? i)

Returns true if the given time entity with the day-of-week property falls on a Friday, otherwise false.

+

gap

(gap i oi)

Gets the gap between this interval and the other one or nil

+

hours

(hours i)

Returns a Duration of i hours.

+

instant

(instant)(instant arg0)(instant arg0 arg1)

Creates an Instant. The following arguments are supported:

+
    +
  • no arguments - current instant
  • +
  • one argument +
      +
    • clock
    • +
    • java.util.Date/Calendar
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • millis from epoch
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    +
  • +
+

instant->sql-timestamp

(instant->sql-timestamp instant-or-millis)

Creates a java.sql.Timestamp from the provided instant-or-millis - a millisecond numeric time value or something convertible to an Instant.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Timestamp if your drivers support them.

+

java.sql.Timestamp is a version of a java.util.Date supposed to be used as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types.

+

instant?

(instant? v)

Returns true if v is an instance of java.time.Instant, otherwise false.

+

interval

(interval o)(interval a b)

Constructs an interval out of a string, start and end instants or a start + duration:

+
(j/interval "2010-01-01T00:00:00Z/2013-01-01T00:00:00Z")
 => #<Interval 2010-01-01T00:00:00Z/2013-01-01T00:00:00Z>
 
 (j/interval (j/instant 100000) (j/instant 1000000))
 => #<Interval 1970-01-01T00:01:40Z/1970-01-01T00:16:40Z>
 
 (j/interval (j/instant 100000) (j/duration 15 :minutes))
-=> #<Interval 1970-01-01T00:01:40Z/1970-01-01T00:16:40Z>

interval?

(interval? o)
True if `Interval`
-

iterate

(iterate f initial v & vs)
Returns a lazy sequence of `initial` , `(apply f initial v vs)`, etc.
-
-Useful when you want to produce a sequence of temporal entities, for
-example:
-
-  (iterate plus (days 0) 1)
-  => (#<Period P0D> #<Period P1D> #<Period P2D> ...)
-
-  (iterate plus (local-date 2010 1 1) (years 1))
-  => (#<LocalDate 2010-01-01> #<LocalDate 2011-01-01> ...)
-
-  (iterate adjust (local-date 2010 1 1) :next-working-day)
-  => (#<LocalDate 2010-01-01> #<LocalDate 2010-01-04> ...)

java-date

(java-date)(java-date a)(java-date a b)
Creates a `java.util.Date` out of any combination of arguments valid for
-`java-time/instant` or the Instant itself.
-
-A `java.util.Date` represents an instant in time. It's a direct analog of the
-`java.time.Instant` type introduced in the JSR-310. Please consider using the
-`java.time.Instant` (through `java-time/instant`) directly.

largest-min-value

(largest-min-value p)
Largest minimum value of this property
-

leap?

(leap? o)
True if the year of this entity is a leap year.
-

local-date

(local-date)(local-date arg_1_8052)(local-date arg_1_8053 arg_2_8054)(local-date arg_1_8055 arg_2_8056 arg_3_8057)
Creates a `LocalDate`. The following arguments are supported:
-
-* no arguments - current local-date
-* one argument
-  + clock
-  + another temporal entity
-  + string representation
-  + year
-* two arguments
-  + formatter (format) and a string
-  + an instant and a zone id
-  + another temporal entity and an offset (preserves local time)
-  + year and month
-* three arguments
-  + year, month and date

local-date-time

(local-date-time)(local-date-time y m d h)(local-date-time y m d h mm)(local-date-time y m d h mm ss)(local-date-time y m d h mm ss n)(local-date-time arg_1_8120)(local-date-time arg_1_8121 arg_2_8122)(local-date-time arg_1_8123 arg_2_8124 arg_3_8125)
Creates a `LocalDateTime`. The following arguments are supported:
-
-* no arguments - current local date-time
-* one argument
-  + clock
-  + another temporal entity
-  + string representation
-  + year
-* two arguments
-  + local date and local time
-  + an instant and a zone id
-  + formatter (format) and a string
-  + year and month
-
-three and more arguments - year/month/day/...

local-date-time?

(local-date-time? v__7519__auto__)
True if an instance of LocalDateTime.
-

local-date?

(local-date? v__7519__auto__)
True if an instance of LocalDate.
-

local-time

(local-time)(local-time h m s nn)(local-time arg_1_8086)(local-time arg_1_8087 arg_2_8088)(local-time arg_1_8089 arg_2_8090 arg_3_8091)
Creates a `LocalTime`. The following arguments are supported:
-
-* no arguments - current local time
-* one argument
-  + clock
-  + another temporal entity
-  + string representation
-  + hours
-* two arguments
-  + formatter (format) and a string
-  + an instant and a zone id
-  + hours and minutes
-* three/four arguments - hour, minute, second, nanos

local-time?

(local-time? v__7519__auto__)
True if an instance of LocalTime.
-

max

(max o & os)
Latest/longest of the given time entities. Entities should be of the same
-type

max-value

(max-value p)
Maximum value of this property, e.g. 29th of February for months
-

micros

(micros micros)
Duration of a specified number of microseconds.
-

millis

(millis v__8353__auto__)
Duration of a specified number of millis.
-

min

(min o & os)
Earliest/shortest of the given time entities. Entities should be of the same
-type

min-value

(min-value p)
Minimum value of this property
-

minus

(minus o & os)
Subtracts all of the `os` from the time entity `o`
-
-(j/minus (j/local-date 2015) (j/years 1))
-=> <java.time.LocalDate "2014-01-01">

minutes

(minutes v__8353__auto__)
Duration of a specified number of minutes.
-

monday?

(monday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a monday.

month

(month)(month v__8876__auto__)(month fmt__8877__auto__ arg__8878__auto__)
Returns the `Month` for the given month keyword name (e.g. `:january`),
-ordinal or entity. Current month if no arguments given.

month-day

(month-day)(month-day G__8993)(month-day a__8918__auto__ b__8919__auto__)
Returns the `MonthDay` for the given entity, string, clock, zone or
-month/day combination. Current month-day if no arguments given.

month-day?

(month-day? o__8915__auto__)

month?

(month? o__8875__auto__)

months

(months v__8370__auto__)

move-end-by

(move-end-by i & os)
Moves the end instant of the interval by the sum of given
-periods/durations/numbers of milliseconds.
-
-  (move-start-by (interval 0 10000) (millis 1000) (seconds 1))
-  => #<Interval ...:00Z/...:12Z>
-
-Fails if the new end instant falls before the start instant.
-
-  (move-end-by (interval 0 10000) (millis -11000))
-  => DateTimeException...

move-end-to

(move-end-to i new-end)
Moves the end of the interval to the given instant (or something
- convertible to an instant):
-
- (move-end-to (interval 0 10000) (instant 15000))
- => #<Interval ...:00Z/...:15Z>
-
-Fails if the new end instant falls before the start instant:
-
- (move-end-to (interval 0 10000) (millis -1))
- => DateTimeException...

move-start-by

(move-start-by i & os)
Moves the start instant of the interval by the sum of given
-periods/durations/numbers of milliseconds:
-
-  (move-start-by (interval 0 10000) (millis 1000) (seconds 1))
-  => #<Interval ...:02Z/...:10Z>
-
-Fails if the new start instant falls after the end instant.
-
-  (move-start-by (interval 0 10000) (millis 11000))
-  ; => DateTimeException...

move-start-to

(move-start-to i new-start)
Moves the start instant of the interval to the given instant (or something
- convertible to an instant):
-
- (move-start-to (interval 0 10000) (instant 5000))
- => #<Interval ...:05Z/...:10Z>
-
-Fails if the new start instant falls after the end instant:
-
- (move-start-to (interval 0 10000) (millis 15000))
- => DateTimeException...

multiply-by

(multiply-by o v)
Entity `o` mutlitplied by the value `v`
-

nanos

(nanos v__8353__auto__)
Duration of a specified number of nanos.
-

negate

(negate a)
Negates a temporal amount:
-
-(negate (negate x)) == x

negative?

(negative? a)
True if the amount is negative
-

offset-clock

(offset-clock d)(offset-clock c d)
Creates a clock offset from the current/provided clock by a given
-`duration`.

offset-date-time

(offset-date-time)(offset-date-time y m d h)(offset-date-time y mo d h m)(offset-date-time y mo d h m s)(offset-date-time y mo d h m s n)(offset-date-time y mo d h m s n o)(offset-date-time arg_1_8536)(offset-date-time arg_1_8537 arg_2_8538)(offset-date-time arg_1_8539 arg_2_8540 arg_3_8541)
Creates an `OffsetDateTime`. The following arguments are supported:
-
-  * no arguments - current date-time with the default offset
-  * one argument
-    + clock
-    + another temporal entity
-    + string representation
-    + year
-  * two arguments
-    + formatter (format) and a string
-    + local date-time and an offset
-    + another temporal entity and an offset (preserves local time)
-    + year and month
-  * three arguments
-    + local date, local time and an offset
-    + year, month and date
-  * four up to seven arguments - position date-time constructors
-  * eight arguments - time fields up to nanoseconds and a zone offset
-
-If zone offset is not specified, default will be used. You can check the
-default offset by invoking `(zone-offset)`.

offset-date-time?

(offset-date-time? v__7519__auto__)
True if an instance of OffsetDateTime.
-

offset-time

(offset-time)(offset-time h m s)(offset-time h m s n)(offset-time h m s n o)(offset-time arg_1_8570)(offset-time arg_1_8571 arg_2_8572)
Creates an `OffsetTime`. The following arguments are supported:
-
-  * no arguments - current time with the default offset
-  * one argument
-    + clock
-    + zone id
-    + another temporal entity
-    + string representation
-    + hour
-  * two arguments
-    + formatter (format) and a string
-    + local time and an offset
-    + instant and an offset
-    + hour and minutes
-  * three arguments - hours, minutes, seconds
-  * four arguments - hours, minutes, seconds, nanos
-  * five arguments - last is the offset
-
-If zone offset is not specified, default will be used. You can check the
-default offset by invoking `(zone-offset)`.

offset-time?

(offset-time? v__7519__auto__)
True if an instance of OffsetTime.
-

overlap

(overlap i oi)
Gets the overlap between this interval and the other one or `nil`
-

overlaps?

(overlaps? i oi)
True if this interval overlaps the other one
-

period

(period)(period arg_1_8383)(period arg_1_8384 arg_2_8385)(period arg_1_8386 arg_2_8387 arg_3_8388)
Creates a period - a temporal entity consisting of years, months and days.
-
-Given one argument will
-  * interpret as years if a number
-  * try to parse from the standard format if a string
-  * extract supported units from another `TemporalAmount`
-  * convert from a Joda Period
-
-Given two arguments will
-  * get a period of a specified unit, e.g. `(period 10 :months)`
-  * get a period between two temporals by converting them to local dates
-  * get a period of a specified number of years and months
-
-Given three arguments will create a year/month/day period.

period?

(period? v__7519__auto__)
True if an instance of Period.
-

plus

(plus o & os)
Adds all of the `os` to the time entity `o`
-
-(j/plus (j/local-date 2015) (j/years 1))
-=> <java.time.LocalDate "2016-01-01">

properties

(properties o)
Map of properties present in this temporal entity
-

property

(property o k)
Property of this temporal entity under key `k`
-

quarter

(quarter)(quarter v__8876__auto__)(quarter fmt__8877__auto__ arg__8878__auto__)
Returns the `Quarter` for the given quarter keyword name (e.g. `:q1`),
-ordinal or entity. Current quarter if no arguments given.

quarter?

(quarter? o__8875__auto__)

range

(range p)
Range of values for this property
-

saturday?

(saturday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a saturday.

seconds

(seconds v__8353__auto__)
Duration of a specified number of seconds.
-

smallest-max-value

(smallest-max-value p)
Smallest maximum value of this property, e.g. 28th of February for months
-

sql-date

(sql-date)(sql-date G__9570)(sql-date G__9571 G__9572)(sql-date G__9573 G__9574 G__9575)
Creates a `java.sql.Date` out of any combination of arguments valid for
-`java-time/local-date` or the LocalDate itself.
-
-Please consider using the JSR-310 Java Time types instead of `java.sql.Date`
-if your drivers support them.
-
-Even though `java.sql.Date` extends a `java.util.Date`, it's supposed to be
-used as a local date (no time component or timezone) for the purposes of
-conversion from/to native JDBC driver DATE types.

sql-time

(sql-time)(sql-time G__9606)(sql-time G__9607 G__9608)(sql-time G__9609 G__9610 G__9611)
Creates a `java.sql.Time` out of any combination of arguments valid for
-`java-time/local-time` (except the nanos constructor) or the LocalTime
-itself.
-
-Please consider using the JSR-310 Java Time types instead of `java.sql.Time`
-if your drivers support them.
-
-Even though `java.sql.Time` extends a `java.util.Date`, it's supposed to be
-used as a local time (no date component or timezone) for the purposes of
-conversion from/to native JDBC driver TIME types.

sql-timestamp

(sql-timestamp)(sql-timestamp G__9577)(sql-timestamp G__9578 G__9579)(sql-timestamp G__9580 G__9581 G__9582)(sql-timestamp G__9583 G__9584 G__9585 G__9586)(sql-timestamp G__9587 G__9588 G__9589 G__9590 G__9591)(sql-timestamp G__9592 G__9593 G__9594 G__9595 G__9596 G__9597)(sql-timestamp G__9598 G__9599 G__9600 G__9601 G__9602 G__9603 G__9604)
Creates a `java.sql.Timestamp` out of any combination of arguments valid for
-`java-time/local-date-time` or the LocalDateTime itself.
-
-Please consider using the JSR-310 Java Time types instead of
-`java.sql.Timestamp` if your drivers support them.
-
-`java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used
-as a local date-time (no timezone) for the purposes of conversion from/to native
-JDBC driver TIMESTAMP types.

standard-days

(standard-days v__8353__auto__)
Duration of a specified number of days.
-

start

(start i)
Gets the start instant of the interval
-

sunday?

(sunday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a sunday.

supports?

(supports? o p)
True if the `o` entity supports the `p` property
-

system-clock

(system-clock)(system-clock k)
Creates a system clock. In the default timezone if called without arguments,
-otherwise accepts a Zone Id.

thursday?

(thursday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a thursday.

tick-clock

(tick-clock d)(tick-clock c d)
Creates a clock wrapping system/provided clock that only ticks as per
-specified duration.

time-between

(time-between o e u)
Time between temporal entities `o` and `e` in unit `u`.
-
-(j/time-between (j/local-date 2015) (j/local-date 2016) :days)
+=> #<Interval 1970-01-01T00:01:40Z/1970-01-01T00:16:40Z>
+
+

Requires the optional threeten-extra dependency.

+

interval?

(interval? o)

True if Interval

+

iterate

(iterate f initial v & vs)

Returns a lazy sequence of initial , (apply f initial v vs), etc.

+

Useful when you want to produce a sequence of temporal entities, for example:

+
(iterate plus (days 0) 1)
+=> (#<Period P0D> #<Period P1D> #<Period P2D> ...)
+
+(iterate plus (local-date 2010 1 1) (years 1))
+=> (#<LocalDate 2010-01-01> #<LocalDate 2011-01-01> ...)
+
+(iterate adjust (local-date 2010 1 1) :next-working-day)
+=> (#<LocalDate 2010-01-01> #<LocalDate 2010-01-04> ...)
+
+

java-date

(java-date)(java-date a)(java-date a b)

Creates a java.util.Date out of any combination of arguments valid for instant or the Instant itself.

+

A java.util.Date represents an instant in time. It’s a direct analog of the java.time.Instant type introduced in the JSR-310. Please consider using the java.time.Instant (through instant) directly.

+

largest-min-value

(largest-min-value p)

Largest minimum value of this property

+

leap?

(leap? o)

True if the year of this entity is a leap year.

+

local-date

(local-date)(local-date arg0)(local-date arg0 arg1)(local-date arg0 arg1 arg2)

Creates a LocalDate. The following arguments are supported:

+
    +
  • no arguments - current local-date
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • an instant and a zone id
    • +
    • another temporal entity and an offset (preserves local time)
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • year, month and date
    • +
    +
  • +
+

local-date-time

(local-date-time)(local-date-time y m d h)(local-date-time y m d h mm)(local-date-time y m d h mm ss)(local-date-time y m d h mm ss n)(local-date-time arg0)(local-date-time arg0 arg1)(local-date-time arg0 arg1 arg2)

Creates a LocalDateTime. The following arguments are supported:

+
    +
  • no arguments - current local date-time
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • local date and local time
    • +
    • an instant and a zone id
    • +
    • formatter (format) and a string
    • +
    • year and month
    • +
    +
  • +
  • +

    three and more arguments - year/month/day/…

    +
  • +
+

local-date-time?

(local-date-time? v)

Returns true if v is an instance of java.time.LocalDateTime, otherwise false.

+

local-date?

(local-date? v)

Returns true if v is an instance of java.time.LocalDate, otherwise false.

+

local-time

(local-time)(local-time h m s nn)(local-time arg0)(local-time arg0 arg1)(local-time arg0 arg1 arg2)

Creates a LocalTime. The following arguments are supported:

+
    +
  • no arguments - current local time
  • +
  • one argument +
      +
    • clock
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • hours
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • an instant and a zone id
    • +
    • hours and minutes
    • +
    +
  • +
  • three/four arguments - hour, minute, second, nanos
  • +
+

local-time?

(local-time? v)

Returns true if v is an instance of java.time.LocalTime, otherwise false.

+

max

(max o & os)

Latest/longest of the given time entities. Entities should be of the same type

+

max-value

(max-value p)

Maximum value of this property, e.g. 29th of February for months

+

micros

(micros micros)

Duration of a specified number of microseconds.

+

millis

(millis i)

Returns a Duration of i millis.

+

min

(min o & os)

Earliest/shortest of the given time entities. Entities should be of the same type

+

min-value

(min-value p)

Minimum value of this property

+

minus

(minus o & os)

Subtracts all of the os from the time entity o

+
(j/minus (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2014-01-01">
+
+

minutes

(minutes i)

Returns a Duration of i minutes.

+

mock-clock

(mock-clock)(mock-clock instant)(mock-clock instant zone)

Returns a mock implementation of the java.time.Clock. The mock supports advance-clock! operation which allows to move the time in the clock, e.g.:

+
(let [clock (mock-clock 0 "UTC")]
+  (with-clock clock
+    (is (= (value clock) 0))
+    (is (= (instant) (instant 0)))
+    (advance-clock! clock (j/millis 1))
+    (is (= (value clock) 1))
+    (is (= (instant) (instant 1)))))
+
+

You can move the clock back via advancing by a negative temporal amount.

+

Creates a clock at epoch in the default time zone when called without arguments.

+

monday?

(monday? i)

Returns true if the given time entity with the day-of-week property falls on a Monday, otherwise false.

+

month

(month)(month v)(month fmt arg)

Returns the Month for the given month keyword name (e.g. :january), ordinal or entity. Current month if no arguments given.

+

month-day

(month-day)(month-day arg)(month-day a b)

Returns the MonthDay for the given entity, string, clock, zone or month/day combination. Current month-day if no arguments given.

+

month-day?

(month-day? o)

Returns true if o is java.time.MonthDay, otherwise false.

+

month?

(month? o)

True if java.time.Month.

+

months

(months i)

Returns a Period of i months.

+

move-end-by

(move-end-by i & os)

Moves the end instant of the interval by the sum of given periods/durations/numbers of milliseconds.

+
(move-start-by (interval 0 10000) (millis 1000) (seconds 1))
+=> #<Interval ...:00Z/...:12Z>
+
+

Fails if the new end instant falls before the start instant.

+
(move-end-by (interval 0 10000) (millis -11000))
+=> DateTimeException...
+
+

move-end-to

(move-end-to i new-end)

Moves the end of the interval to the given instant (or something convertible to an instant):

+
(move-end-to (interval 0 10000) (instant 15000))
+=> #<Interval ...:00Z/...:15Z>
+
+

Fails if the new end instant falls before the start instant:

+
(move-end-to (interval 0 10000) (millis -1))
+=> DateTimeException...
+
+

move-start-by

(move-start-by i & os)

Moves the start instant of the interval by the sum of given periods/durations/numbers of milliseconds:

+
(move-start-by (interval 0 10000) (millis 1000) (seconds 1))
+=> #<Interval ...:02Z/...:10Z>
+
+

Fails if the new start instant falls after the end instant.

+
(move-start-by (interval 0 10000) (millis 11000))
+;=> DateTimeException...
+
+

move-start-to

(move-start-to i new-start)

Moves the start instant of the interval to the given instant (or something convertible to an instant):

+
(move-start-to (interval 0 10000) (instant 5000))
+=> #<Interval ...:05Z/...:10Z>
+
+

Fails if the new start instant falls after the end instant:

+
(move-start-to (interval 0 10000) (millis 15000))
+=> DateTimeException...
+
+

multiply-by

(multiply-by o v)

Entity o multiplied by the value v

+

nanos

(nanos i)

Returns a Duration of i nanos.

+

negate

(negate a)

Negates a temporal amount:

+

(negate (negate x)) == x

+

negative?

(negative? a)

True if the amount is negative

+

not-after?

(not-after? x)(not-after? x y)(not-after? x y & more)

Returns true if time entities are ordered from the earliest to the latest (same semantics as <=), otherwise false.

+
(not-after? (local-date 2009) (local-date 2010) (local-date 2011))
+;=> true
+
+(not-after? (interval (instant 10000) (instant 1000000))
+            (instant 99999999))
+;=> true
+
+

not-before?

(not-before? x)(not-before? x y)(not-before? x y & more)

Returns true if time entities are ordered from the latest to the earliest (same semantics as >=), otherwise false.

+
(not-before? (local-date 2011) (local-date 2010) (local-date 2009))
+;=> true
+
+(not-before? (instant 99999999)
+             (interval (instant 10000) (instant 1000000)))
+;=> true
+
+

offset-clock

(offset-clock d)(offset-clock c d)

Creates a clock offset from the current/provided clock by a given duration.

+

offset-date-time

(offset-date-time)(offset-date-time y m d h)(offset-date-time y mo d h m)(offset-date-time y mo d h m s)(offset-date-time y mo d h m s n)(offset-date-time y mo d h m s n o)(offset-date-time arg0)(offset-date-time arg0 arg1)(offset-date-time arg0 arg1 arg2)

Creates an OffsetDateTime. The following arguments are supported:

+
    +
  • no arguments - current date-time with the default offset
  • +
  • one argument +
      +
    • clock
    • +
    • zone offset
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • local date-time and an offset
    • +
    • another temporal entity and an offset (preserves local time)
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • local date, local time and an offset
    • +
    • year, month and date
    • +
    +
  • +
  • four up to seven arguments - position date-time constructors
  • +
  • eight arguments - time fields up to nanoseconds and a zone offset
  • +
+

If zone offset is not specified, default will be used. You can check the default offset by invoking (zone-offset).

+

offset-date-time?

(offset-date-time? v)

Returns true if v is an instance of java.time.OffsetDateTime, otherwise false.

+

offset-time

(offset-time)(offset-time h m s)(offset-time h m s n)(offset-time h m s n o)(offset-time arg0)(offset-time arg0 arg1)

Creates an OffsetTime. The following arguments are supported:

+
    +
  • no arguments - current time with the default offset
  • +
  • one argument +
      +
    • clock
    • +
    • zone id
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • hour
    • +
    +
  • +
  • two arguments +
      +
    • formatter (format) and a string
    • +
    • local time and an offset
    • +
    • instant and an offset
    • +
    • hour and minutes
    • +
    +
  • +
  • three arguments - hours, minutes, seconds
  • +
  • four arguments - hours, minutes, seconds, nanos
  • +
  • five arguments - last is the offset
  • +
+

If zone offset is not specified, default will be used. You can check the default offset by invoking (zone-offset).

+

offset-time?

(offset-time? v)

Returns true if v is an instance of java.time.OffsetTime, otherwise false.

+

overlap

(overlap i oi)

Gets the overlap between this interval and the other one or nil

+

overlaps?

(overlaps? i oi)

True if this interval overlaps the other one

+

period

(period)(period arg0)(period arg0 arg1)(period arg0 arg1 arg2)

Creates a period - a temporal entity consisting of years, months and days.

+

Given one argument will

+
    +
  • interpret as years if a number
  • +
  • try to parse from the standard format if a string
  • +
  • extract supported units from another TemporalAmount
  • +
  • convert from a Joda Period
  • +
+

Given two arguments will

+
    +
  • get a period of a specified unit, e.g. (period 10 :months)
  • +
  • get a period between two temporals by converting them to local dates
  • +
  • get a period of a specified number of years and months
  • +
+

Given three arguments will create a year/month/day period.

+

period?

(period? v)

Returns true if v is an instance of java.time.Period, otherwise false.

+

plus

(plus o & os)

Adds all of the os to the time entity o. plus is not commutative, the first argument is always the entity which will accumulate the rest of the arguments.

+
(j/plus (j/local-date 2015) (j/years 1))
+=> <java.time.LocalDate "2016-01-01">
+
+

properties

(properties o)

Map of properties present in this temporal entity

+

property

(property o k)

Property of this temporal entity under key k

+

quarter

(quarter)(quarter v)(quarter fmt arg)

Returns the Quarter for the given quarter keyword name (e.g. :q1), ordinal or entity. Current quarter if no arguments given.

+

quarter?

(quarter? o)

True if org.threeten.extra.Quarter.

+

range

(range p)

Range of values for this property

+

saturday?

(saturday? i)

Returns true if the given time entity with the day-of-week property falls on a Saturday, otherwise false.

+

seconds

(seconds i)

Returns a Duration of i seconds.

+

set-clock!

(set-clock! clock time)

Sets the clock to the given time.

+

This mutates the mock clock.

+

smallest-max-value

(smallest-max-value p)

Smallest maximum value of this property, e.g. 28th of February for months

+

sql-date

(sql-date)(sql-date arg0)(sql-date arg0 arg1)(sql-date arg0 arg1 arg2)

Creates a java.sql.Date out of any combination of arguments valid for local-date or the LocalDate itself.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Date if your drivers support them.

+

Even though java.sql.Date extends a java.util.Date, it’s supposed to be used as a local date (no time component or time zone) for the purposes of conversion from/to native JDBC driver DATE types.

+

sql-time

(sql-time)(sql-time arg0)(sql-time arg0 arg1)(sql-time arg0 arg1 arg2)

Creates a java.sql.Time out of any combination of arguments valid for local-time (except the nanos constructor) or the LocalTime itself.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Time if your drivers support them.

+

Even though java.sql.Time extends a java.util.Date, it’s supposed to be used as a local time (no date component or time zone) for the purposes of conversion from/to native JDBC driver TIME types.

+

sql-timestamp

(sql-timestamp)(sql-timestamp arg0)(sql-timestamp arg0 arg1)(sql-timestamp arg0 arg1 arg2)(sql-timestamp arg0 arg1 arg2 arg3)(sql-timestamp arg0 arg1 arg2 arg3 arg4)(sql-timestamp arg0 arg1 arg2 arg3 arg4 arg5)(sql-timestamp arg0 arg1 arg2 arg3 arg4 arg5 arg6)

Creates a java.sql.Timestamp in the local time zone out of any combination of arguments valid for local-date-time or the LocalDateTime itself.

+

Does not support Timestamp construction from an Instant or a long millis value—please use instant->sql-timestamp for this purpose.

+

Please consider using the JSR-310 Java Time types instead of java.sql.Timestamp if your drivers support them.

+

java.sql.Timestamp is a version of a java.util.Date supposed to be used as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types.

+

standard-days

(standard-days i)

Returns a Duration of i days.

+

start

(start i)

Gets the start instant of the interval

+

sunday?

(sunday? i)

Returns true if the given time entity with the day-of-week property falls on a Sunday, otherwise false.

+

supports?

(supports? o p)

True if the o entity supports the p property

+

system-clock

(system-clock)(system-clock k)

Creates a system clock. In the default time zone if called without arguments, otherwise accepts a Zone Id.

+

thursday?

(thursday? i)

Returns true if the given time entity with the day-of-week property falls on a Thursday, otherwise false.

+

tick-clock

(tick-clock d)(tick-clock c d)

Creates a clock wrapping system/provided clock that only ticks as per specified duration.

+

time-between

(time-between o e u)

Time between temporal entities o and e in unit u.

+
(j/time-between (j/local-date 2015) (j/local-date 2016) :days)
 => 365
 
 (j/time-between :days (j/local-date 2015) (j/local-date 2016))
-=> 365

to-java-date

(to-java-date o)
Converts a date entity to a `java.util.Date`.
-
-*Deprecated*:
-This function only has a single arity and works for entities directly
-convertible to `java.time.Instant`. Please consider using `java-date`
-instead.

to-millis-from-epoch

(to-millis-from-epoch o)
Converts a date entity to a `long` representing the number of milliseconds
-from epoch.

to-sql-date

(to-sql-date o)
Converts a local date entity to a `java.sql.Date`.
-
-*Deprecated*:
-This function only has a single arity and works for entities directly
-convertible to `java.time.LocalDate`. Please consider using `sql-date`
-instead.

to-sql-timestamp

(to-sql-timestamp o)
Converts a date entity to a `java.sql.Timestamp`.
-
-*Deprecated*:
-This function only has a single arity and works for entities directly
-convertible to `java.time.Instant`. Please consider using `sql-timestamp`
-instead.

truncate-to

(truncate-to o u)
Truncates this entity to the specified time unit. Only works for units that
-divide into the length of standard day without remainder (up to `:days`).

tuesday?

(tuesday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a tuesday.

unit

(unit k)(unit entity k)
Returns a `TemporalUnit` for the given key `k` or extracts the field from
-the given temporal `entity`.
-
-You can see predefined units via `java-time.repl/show-units`.
-
-If you want to make your own custom TemporalUnits resolvable, you need to rebind the
-`java-time.properties/*units*` to a custom `java-time.properties.UnitGroup`.

unit?

(unit? o)
True if this is a `TemporalUnit`.
-

units

(units o)
Units present in this temporal entity.
-

value

(value p)
Value of the property
-

value-range

(value-range min max)(value-range {:keys [min-smallest min-largest max-smallest max-largest]})
Creates a `ValueRange` given the `min` and `max` amounts or a map of
-`:min-smallest`, `:max-smallest`, `:min-largest` and `:max-largest`.

wednesday?

(wednesday? o__9179__auto__)
Returns true if the given time entity with the
-`day-of-week` property falls on a wednesday.

weekday?

(weekday? dt)

weekend?

(weekend? dt)

weeks

(weeks v__8370__auto__)

with-clock

macro

(with-clock c & forms)
Executes the given `forms` in the scope of the provided `clock`.
-
-All the temporal entities that get created without parameters will inherit
-their values from the clock:
-
-  (with-clock (system-clock "Europe/London")
-    (zone-id))
-  => #<java.time.ZoneRegion Europe/London>

with-clock-fn

(with-clock-fn c f)
Executes the given function in the scope of the provided clock. All the
-temporal entities that get created without parameters will inherit their
-values from the clock.

with-largest-min-value

(with-largest-min-value p)
Underlying temporal entity with the value set to the largest minimum
-available for this property

with-max-value

(with-max-value p)
Underlying temporal entity with the value set to the maximum
-available for this property

with-min-value

(with-min-value p)
Underlying temporal entity with the value set to the minimum available for
-this property

with-offset

(with-offset o offset)
Sets the offset to the specified value ensuring that the local time stays
-the same.
-
-  (offset-time 10 30 0 0 +2)
-  => #<java.time.OffsetTime 10:30+02:00>
-  (with-offset *1 +3)
-  => #<java.time.OffsetTime 10:30+03:00>

with-offset-same-instant

(with-offset-same-instant o offset)
Sets the offset to the specified value ensuring that the result has the same instant, e.g.:
-
-(offset-time 10 30 0 0 +2)
-=> #<java.time.OffsetTime 10:30+02:00>
-(with-offset-same-instant *1 +3)
-=> #<java.time.OffsetTime 11:30+03:00>

with-smallest-max-value

(with-smallest-max-value p)
Underlying temporal entity with the value set to the smallest maximum
-available for this property

with-value

(with-value p v)
Underlying temporal entity with the value of this property set to `v`
-

with-zone

(with-zone o z)
Returns this temporal entity with the specified `ZoneId`
-

with-zone-same-instant

(with-zone-same-instant zdt z)
Sets the zone to the specified value ensuring that the result has the same instant, e.g.:
-
-(zoned-date-time 2015)
-=> #<java.time.ZonedDateTime 2015-01-01T00:00+00:00[Europe/London]>
-(with-zone-same-instant *1 "America/New_York")
-=> #<java.time.ZonedDateTime 2014-12-31T18:00-05:00[America/New_York]>

year

(year)(year G__8982)(year fmt__8905__auto__ arg__8906__auto__)
Returns the `Year` for the given entity, string, clock, zone or number.
-Current year if no arguments given.

year-month

(year-month)(year-month G__9008)(year-month a__8918__auto__ b__8919__auto__)
Returns the `YearMonth` for the given entity, string, clock, zone or
-month/day combination. Current year-month if no arguments given.

year-month?

(year-month? o__8915__auto__)

year-quarter

(year-quarter)(year-quarter G__9094)(year-quarter a__8918__auto__ b__8919__auto__)
Returns the `YearQuarter` for the given entity, clock, zone or year with quarter.
-Current year quarter if no arguments given.

year-quarter?

(year-quarter? o__8915__auto__)

year?

(year? o__8904__auto__)

years

(years v__8370__auto__)

zero?

(zero? a)
True if the amount is zero
-

zone-id

(zone-id)(zone-id arg_1_8512)(zone-id arg_1_8513 arg_2_8514)
Creates a `ZoneId` from a string identifier, `java.util.TimeZone` or extracts
-from another temporal entity.
-
-Returns default system zone id if no arguments provided.
-
-Given two arguments will use the second as the offset.

zone-offset

(zone-offset)(zone-offset o)(zone-offset h m)(zone-offset h m s)
Creates a `ZoneOffset` from a string identifier (e.g. "+01"), a number of
-hours/hours and minutes/hours, minutes and seconds or extracts from another
-temporal entity.
-
-Returns default system zone offset if no arguments provided.

zoned-date-time

(zoned-date-time)(zoned-date-time y m d h)(zoned-date-time y mo d h m)(zoned-date-time y mo d h m s)(zoned-date-time y mo d h m s n)(zoned-date-time y mo d h m s n o)(zoned-date-time arg_1_8593)(zoned-date-time arg_1_8594 arg_2_8595)(zoned-date-time arg_1_8596 arg_2_8597 arg_3_8598)
Creates a `ZonedDateTime`. The following arguments are supported:
-
-  * no arguments - current date-time in the default zone
-  * one argument
-    + clock
-    + zone id
-    + another temporal entity
-    + string representation
-    + year
-  * two arguments
-    + formatter and a string
-    + local date-time and a zone id
-    + year and month
-  * three arguments
-    + local date, local time and a zone id
-    + year, month and day
-  * four to seven arguments - date-time fields
-  * eight arguments - last is the zone id
-
-If zone id is not specified, default zone id will be used. You can check the
-default zone by invoking `(zone-id)`.

zoned-date-time?

(zoned-date-time? v__7519__auto__)
True if an instance of ZonedDateTime.
-
\ No newline at end of file +=> 365 +
+

to-java-date

deprecated

(to-java-date o)

Converts a date entity to a java.util.Date.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.Instant. Please consider using java-date instead.

+

to-millis-from-epoch

(to-millis-from-epoch o)

Converts a date entity to a long representing the number of milliseconds from epoch.

+

to-sql-date

deprecated

(to-sql-date o)

Converts a local date entity to a java.sql.Date.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.LocalDate. Please consider using sql-date instead.

+

to-sql-timestamp

deprecated

(to-sql-timestamp o)

Converts a date entity to a java.sql.Timestamp.

+

Deprecated: This function only has a single arity and works for entities directly convertible to java.time.Instant. Please consider using sql-timestamp instead.

+

truncate-to

(truncate-to o u)

Truncates this entity to the specified time unit. Only works for units that divide into the length of standard day without remainder (up to :days).

+

tuesday?

(tuesday? i)

Returns true if the given time entity with the day-of-week property falls on a Tuesday, otherwise false.

+

unit

(unit k)(unit entity k)

Returns a TemporalUnit for the given key k or extracts the field from the given temporal entity.

+

You can see predefined units via java-time.repl/show-units.

+

If you want to make your own custom TemporalUnits resolvable, you need to rebind the java-time.properties/*units* to a custom java_time.properties.UnitGroup.

+

unit?

(unit? o)

True if this is a TemporalUnit.

+

units

(units o)

Units present in this temporal entity.

+

value

(value p)

Value of the property

+

value-range

(value-range min max)(value-range arg0)

Creates a ValueRange given the min and max amounts or a map of :min-smallest, :max-smallest, :min-largest and :max-largest.

+

wednesday?

(wednesday? i)

Returns true if the given time entity with the day-of-week property falls on a Wednesday, otherwise false.

+

weekday?

(weekday? dt)

Complement of weekend?.

+

weekend?

(weekend? dt)

Returns true if argument is saturday? or sunday?, otherwise false.

+

weeks

(weeks i)

Returns a Period of i weeks.

+

when-joda-time-loaded

macro

(when-joda-time-loaded & body)

Execute the body when Joda-Time classes are found on the classpath.

+

Take care - when AOT-compiling code using this macro, the Joda-Time classes must be on the classpath at compile time!

+

with-clock

macro

(with-clock c & forms)

Executes the given forms in the scope of the provided clock.

+

All the temporal entities that get created without parameters will inherit their values from the clock:

+

(with-clock (system-clock “Europe/London”) (zone-id)) => #<java.time.ZoneRegion Europe/London>

+

with-clock-fn

(with-clock-fn c f)

Executes the given function in the scope of the provided clock. All the temporal entities that get created without parameters will inherit their values from the clock.

+

with-largest-min-value

(with-largest-min-value p)

Underlying temporal entity with the value set to the largest minimum available for this property

+

with-max-value

(with-max-value p)

Underlying temporal entity with the value set to the maximum available for this property

+

with-min-value

(with-min-value p)

Underlying temporal entity with the value set to the minimum available for this property

+

with-offset

(with-offset o offset)

Sets the offset to the specified value ensuring that the local time stays the same.

+

(offset-time 10 30 0 0 +2) => #<java.time.OffsetTime 10:30+02:00> (with-offset *1 +3) => #<java.time.OffsetTime 10:30+03:00>

+

with-offset-same-instant

(with-offset-same-instant o offset)

Sets the offset to the specified value ensuring that the result has the same instant, e.g.:

+

(offset-time 10 30 0 0 +2) => #<java.time.OffsetTime 10:30+02:00> (with-offset-same-instant *1 +3) => #<java.time.OffsetTime 11:30+03:00>

+

with-smallest-max-value

(with-smallest-max-value p)

Underlying temporal entity with the value set to the smallest maximum available for this property

+

with-value

(with-value p v)

Underlying temporal entity with the value of this property set to v

+

with-zone

(with-zone o z)

Returns this temporal entity with the specified ZoneId

+

with-zone-same-instant

(with-zone-same-instant zdt z)

Sets the zone to the specified value ensuring that the result has the same instant, e.g.:

+

(zoned-date-time 2015) => #<java.time.ZonedDateTime 2015-01-01T00:00+00:00Europe/London> (with-zone-same-instant *1 “America/New_York”) => #<java.time.ZonedDateTime 2014-12-31T18:00-05:00America/New_York>

+

year

(year)(year arg)(year fmt arg)

Returns the Year for the given entity, string, clock, zone or number. Current year if no arguments given.

+

year-month

(year-month)(year-month arg)(year-month a b)

Returns the YearMonth for the given entity, string, clock, zone or month/day combination. Current year-month if no arguments given.

+

year-month?

(year-month? o)

Returns true if o is java.time.YearMonth, otherwise false.

+

year-quarter

(year-quarter)(year-quarter arg)(year-quarter a b)

Returns the YearQuarter for the given entity, clock, zone or year with quarter. Current year quarter if no arguments given.

+

year-quarter?

(year-quarter? o)

Returns true if o is org.threeten.extra.YearQuarter, otherwise false.

+

year?

(year? o)

Returns true if o is java.time.Year, otherwise false.

+

years

(years i)

Returns a Period of i years.

+

zero?

(zero? a)

True if the amount is zero

+

zone-id

(zone-id)(zone-id arg0)(zone-id arg0 arg1)

Creates a ZoneId from a string identifier, java.util.TimeZone or extracts from another temporal entity.

+

Returns default system zone id if no arguments provided.

+

Given two arguments will use the second as the offset.

+

zone-id?

(zone-id? v)

Returns true if v is an instance of java.time.ZoneId, otherwise false.

+

zone-offset

(zone-offset)(zone-offset o)(zone-offset h m)(zone-offset h m s)

Creates a ZoneOffset from a string identifier (e.g. “+01”), a number of hours/hours and minutes/hours, minutes and seconds or extracts from another temporal entity.

+

Returns default system zone offset if no arguments provided.

+

zoned-date-time

(zoned-date-time)(zoned-date-time y m d h)(zoned-date-time y mo d h m)(zoned-date-time y mo d h m s)(zoned-date-time y mo d h m s n)(zoned-date-time y mo d h m s n o)(zoned-date-time arg0)(zoned-date-time arg0 arg1)(zoned-date-time arg0 arg1 arg2)

Creates a ZonedDateTime. The following arguments are supported:

+
    +
  • no arguments - current date-time in the default zone
  • +
  • one argument +
      +
    • clock
    • +
    • zone id
    • +
    • another temporal entity
    • +
    • string representation
    • +
    • year
    • +
    +
  • +
  • two arguments +
      +
    • formatter and a string
    • +
    • local date-time and a zone id
    • +
    • year and month
    • +
    +
  • +
  • three arguments +
      +
    • local date, local time and a zone id
    • +
    • year, month and day
    • +
    +
  • +
  • four to seven arguments - date-time fields
  • +
  • eight arguments - last is the zone id
  • +
+

If zone id is not specified, default zone id will be used. You can check the default zone by invoking (zone-id).

+

zoned-date-time?

(zoned-date-time? v)

Returns true if v is an instance of java.time.ZonedDateTime, otherwise false.

+
\ No newline at end of file diff --git a/docs/java-time.repl.html b/docs/java-time.repl.html index 45da642..8defccb 100644 --- a/docs/java-time.repl.html +++ b/docs/java-time.repl.html @@ -1,3 +1,3 @@ -java-time.repl documentation

java-time.repl

show-adjusters

(show-adjusters)

show-fields

(show-fields)

show-formatters

(show-formatters)

show-graph

(show-graph)

show-path

(show-path from to)

show-timezones

(show-timezones)

show-units

(show-units)
\ No newline at end of file +java-time.repl documentation

java-time.repl

show-adjusters

(show-adjusters)

show-fields

(show-fields)

show-formatters

(show-formatters)

show-graph

(show-graph)

show-path

(show-path from to)

show-timezones

(show-timezones)

show-units

(show-units)
\ No newline at end of file diff --git a/project.clj b/project.clj index cf969f7..a9803fa 100644 --- a/project.clj +++ b/project.clj @@ -1,35 +1,83 @@ -(defproject clojure.java-time "0.3.4-SNAPSHOT" +(require '[clojure.string :as str]) +(def clojure-versions ["1.8" "1.9" "1.10" "1.11" "1.12"]) +(def threeten-extra-version "1.4") +(def joda-time-version "2.10.1") +(def math-combinatorics-version "0.2.0") +(defproject clojure.java-time "1.4.4-SNAPSHOT" :description "Clojure wrapper for Java 8 Time API" :url "http://github.com/dm3/clojure.java-time" :license {:name "MIT License" :url "http://opensource.org/licenses/MIT"} :scm {:name "git" :url "http://github.com/dm3/clojure.java-time"} - :dependencies [[org.clojure/clojure "1.10.3" :scope "provided"]] + :dependencies [[org.clojure/clojure "1.11.1" :scope "provided"]] + :plugins [[lein-codox "0.10.8"] + [lein-shell "0.5.0"] + [jonase/eastwood "1.2.3"]] + :release-tasks [["clean"] + ["vcs" "assert-committed"] + ["change" "version" "leiningen.release/bump-version" "release"] + ["doc"] + ["shell" "./bin/-release-readme+changelog.clj"] + ["vcs" "commit"] + ["vcs" "tag" "--no-sign"] + ["deploy" "clojars"] + ["change" "version" "leiningen.release/bump-version"] + ["vcs" "commit"] + ["vcs" "push"]] :profiles {:dev {:dependencies [[criterium "0.4.4"] - [com.taoensso/timbre "4.1.4"] - [org.clojure/tools.namespace "0.2.11"] - [joda-time/joda-time "2.9.4"] - [org.threeten/threeten-extra "1.2"]] - :plugins [[lein-codox "0.10.3"]] - :codox {:namespaces [java-time java-time.repl] - :doc-files ["README.md" "CHANGELOG.md"]} + [com.taoensso/timbre "5.2.1"] + [com.taoensso/tufte "2.2.0"] + [org.clojure/tools.namespace "1.3.0"] + [joda-time/joda-time ~joda-time-version] + [org.threeten/threeten-extra ~threeten-extra-version] + [org.clojure/math.combinatorics ~math-combinatorics-version]] :source-paths ["dev"] - :global-vars {*warn-on-reflection* true}} + :global-vars {*warn-on-reflection* true} + :eastwood {:exclude-namespaces [java-time + java-time.api + ;;FIXME + java-time.api-test + java-time.test-utils] + :exclude-linters []}} + ;; lein doc + :codox {:injections [(require 'java-time) + (require 'java-time.dev.gen) + (java-time.dev.gen/spit-java-time-ns)] + :codox {:namespaces [java-time java-time.api java-time.repl] + :doc-files ["README.md" "CHANGELOG.md"] + :metadata {:doc/format :markdown} + :output-path "docs" + :source-uri "https://github.com/dm3/clojure.java-time/blob/{git-commit}/{filepath}#L{line}"}} :async-profiler {:jvm-opts ["-Djdk.attach.allowAttachSelf" "-XX:+UnlockDiagnosticVMOptions" "-XX:+DebugNonSafepoints"] :dependencies [[com.clojure-goes-fast/clj-async-profiler "0.3.1"]]} + :test {:dependencies [[org.clojure/math.combinatorics ~math-combinatorics-version]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]} :1.8-three-ten-joda {:dependencies [[org.clojure/clojure "1.8.0"] - [org.threeten/threeten-extra "1.4"] - [joda-time/joda-time "2.10.1"]]} + [org.threeten/threeten-extra ~threeten-extra-version] + [joda-time/joda-time ~joda-time-version]]} :1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]} :1.9-three-ten-joda {:dependencies [[org.clojure/clojure "1.9.0"] - [org.threeten/threeten-extra "1.4"] - [joda-time/joda-time "2.10.1"]]} - :1.10 {:dependencies [[org.clojure/clojure "1.10.0"]]} - :1.10-three-ten-joda {:dependencies [[org.clojure/clojure "1.10.0"] - [org.threeten/threeten-extra "1.4"] - [joda-time/joda-time "2.10.1"]]}} - :aliases {"test-all" ["do" - ["with-profile" "1.8:1.9:1.10:1.8-three-ten-joda:1.9-three-ten-joda:1.10-three-ten-joda" "test"]]}) + [org.threeten/threeten-extra ~threeten-extra-version] + [joda-time/joda-time ~joda-time-version]]} + :1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]} + :1.10-three-ten-joda {:dependencies [[org.clojure/clojure "1.10.3"] + [org.threeten/threeten-extra ~threeten-extra-version] + [joda-time/joda-time ~joda-time-version]]} + :1.11 {:dependencies [[org.clojure/clojure "1.11.1"]]} + :1.11-three-ten-joda {:dependencies [[org.clojure/clojure "1.11.4"] + [org.threeten/threeten-extra ~threeten-extra-version] + [joda-time/joda-time ~joda-time-version]] + :repositories [["sonatype-oss-public" {:url "https://oss.sonatype.org/content/groups/public"}]]} + :1.12 {:dependencies [[org.clojure/clojure "1.12.1"]]} + :1.12-three-ten-joda {:dependencies [[org.clojure/clojure "1.12.1"] + [org.threeten/threeten-extra ~threeten-extra-version] + [joda-time/joda-time ~joda-time-version]]}} + :aliases {"all" ["with-profile" ~(str "test," (str/join ":" (mapcat (juxt identity #(str % "-three-ten-joda")) clojure-versions)))] + "warm-deps" ["all" "deps"] + "doc" ["do" + ["with-profile" "-user,+codox" "codox"] + ;; regenerating api namespaces seems to happen after codox generates + ["with-profile" "-user,+codox" "codox"]] + "test-all" ["all" "test"]}) diff --git a/src/java_time.clj b/src/java_time.clj index bbffa58..2c78f2e 100644 --- a/src/java_time.clj +++ b/src/java_time.clj @@ -1,83 +1,723 @@ -(ns java-time - (:refer-clojure :exclude (zero? range iterate max min contains? format abs)) - (:require [java-time.potemkin.namespaces :as potemkin] - [java-time.util :as jt.u] - [java-time core properties temporal amount zone single-field local chrono - convert sugar seqs adjuster interval format joda clock pre-java8 mock])) - -(potemkin/import-vars - [java-time.clock - with-clock with-clock-fn] - - [java-time.core - zero? negative? negate abs max min - before? not-after? after? not-before? - supports? chronology fields units properties property - as value range min-value max-value largest-min-value smallest-max-value - with-value with-min-value with-max-value with-largest-min-value with-smallest-max-value - truncate-to time-between with-zone leap? - plus minus multiply-by] - - [java-time.amount - duration period period? duration? - nanos micros millis seconds minutes hours standard-days - days weeks months years] - - [java-time.properties - unit? unit field? field] - - [java-time.temporal - value-range instant instant?] - - [java-time.local - local-date local-date-time local-time - local-date? local-date-time? local-time?] - - [java-time.single-field - year year? month month? day-of-week day-of-week? month-day month-day? - year-month year-month?] - - [java-time.zone - available-zone-ids zone-id zone-offset - offset-date-time offset-time zoned-date-time - system-clock fixed-clock offset-clock tick-clock clock? - zone-id? zoned-date-time? offset-date-time? offset-time? - with-zone-same-instant with-offset with-offset-same-instant] - - [java-time.mock - mock-clock advance-clock! set-clock!] - - [java-time.convert - as-map convert-amount to-java-date to-sql-date to-sql-timestamp - to-millis-from-epoch] - - [java-time.sugar - monday? tuesday? wednesday? thursday? friday? saturday? sunday? - weekend? weekday?] - - [java-time.seqs - iterate] - - [java-time.adjuster - adjust] - - [java-time.format - format formatter] - - [java-time.pre-java8 - java-date sql-date sql-timestamp instant->sql-timestamp sql-time] - - [java-time.interval - move-start-to move-end-to move-start-by move-end-by - start end contains? overlaps? abuts? overlap gap] - - [java-time.util - when-joda-time-loaded]) - -(jt.u/when-threeten-extra - (potemkin/import-vars - [java-time.interval interval interval?] - - [java-time.single-field - am-pm am-pm? quarter quarter? day-of-month day-of-month? - day-of-year day-of-year? year-quarter year-quarter?])) +;; NOTE: This namespace is generated by java-time.dev.gen +(ns ^{:deprecated "1.1.0", :doc "This namespace has been deprecated due to [#91](https://github.com/dm3/clojure.java-time/issues/91). + Please migrate to [[java-time.api]] + + This namespace will continue to exist and be updated. For + maximum JVM compatibility, please migrate to `java-time.api`, + which provides the same interface. `java-time` and `java-time.api` + and can be freely intermixed within the same library, so you can + safely migrate your own code even if your dependencies use the old namespace. + + Migration steps: + + 1. rename all references from `java-time` to [[java-time.api]]. + eg., `(:require [java-time :as jt])` => `(:require [java-time.api :as jt])`", :superseded-by "java-time.api"} java-time (:refer-clojure :exclude (zero? range iterate max min contains? format abs < > <= >= = * - + neg?)) (:require [java-time core properties temporal amount zone single-field local chrono convert sugar seqs adjuster interval format joda clock pre-java8 mock])) +(defmacro ^{:doc "Executes the given `forms` in the scope of the provided `clock`. + + All the temporal entities that get created without parameters will inherit + their values from the clock: + + (with-clock (system-clock \"Europe/London\") + (zone-id)) + => #"} with-clock [c & forms] (list* (quote java-time.clock/with-clock) c forms)) +(defmacro ^{:doc "Execute the `body` when Joda-Time classes are found on the classpath. + + Take care - when AOT-compiling code using this macro, the Joda-Time classes + must be on the classpath at compile time!"} when-joda-time-loaded [& body] (list* (quote java-time.util/when-joda-time-loaded) body)) +(def ^{:arglists (quote ([^Clock c f])), :doc "Executes the given function in the scope of the provided clock. All the + temporal entities that get created without parameters will inherit their + values from the clock."} with-clock-fn java-time.clock/with-clock-fn) +(defn ^{:doc "True if the amount is zero"} zero? ([a] (java-time.core/zero? a))) +(defn ^{:doc "True if the amount is negative"} negative? ([a] (java-time.core/negative? a))) +(defn ^{:doc "Negates a temporal amount: + + (negate (negate x)) == x"} negate ([a] (java-time.core/negate a))) +(defn ^{:doc "Returns the absolute value of a temporal amount: + + (abs (negate x)) == (abs x)"} abs ([a] (java-time.core/abs a))) +(def ^{:arglists (quote ([o & os])), :doc "Latest/longest of the given time entities. Entities should be of the same + type"} max java-time.core/max) +(def ^{:arglists (quote ([o & os])), :doc "Earliest/shortest of the given time entities. Entities should be of the same + type"} min java-time.core/min) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. + + ``` + (before? (local-date 2009) (local-date 2010) (local-date 2011)) + => true + + (before? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```"} before? java-time.core/before?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (not-after? (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (not-after? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```"} not-after? java-time.core/not-after?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. + + ``` + (after? (local-date 2011) (local-date 2010) (local-date 2009)) + => true + + (after? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```"} after? java-time.core/after?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (not-before? (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (not-before? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```"} not-before? java-time.core/not-before?) +(defn ^{:doc "True if the `o` entity supports the `p` property"} supports? ([o p] (java-time.core/supports? o p))) +(defn ^{:doc "Fields present in this temporal entity"} fields ([o] (java-time.core/fields o))) +(defn ^{:doc "Units present in this temporal entity."} units ([o] (java-time.core/units o))) +(defn ^{:doc "Map of properties present in this temporal entity"} properties ([o] (java-time.core/properties o))) +(defn ^{:doc "Property of this temporal entity under key `k`"} property ([o k] (java-time.core/property o k))) +(def ^{:arglists (quote ([o k] [o k1 k2] [o k1 k2 & ks])), :doc "Values of property/unit identified by keys/objects `ks` of the temporal + entity `o`, e.g. + + ``` + (as (duration 1 :hours) :minutes) + => 60 + + (as (local-date 2015 9) :year :month-of-year) + => [2015 9] + ```"} as java-time.core/as) +(defn ^{:doc "Value of the property"} value ([p] (java-time.core/value p))) +(defn ^{:doc "Range of values for this property"} range ([p] (java-time.core/range p))) +(defn ^{:doc "Minimum value of this property"} min-value ([p] (java-time.core/min-value p))) +(defn ^{:doc "Maximum value of this property, e.g. 29th of February for months"} max-value ([p] (java-time.core/max-value p))) +(defn ^{:doc "Largest minimum value of this property"} largest-min-value ([p] (java-time.core/largest-min-value p))) +(defn ^{:doc "Smallest maximum value of this property, e.g. 28th of February for months"} smallest-max-value ([p] (java-time.core/smallest-max-value p))) +(defn ^{:doc "Truncates this entity to the specified time unit. Only works for units that + divide into the length of standard day without remainder (up to `:days`)."} truncate-to ([o u] (java-time.core/truncate-to o u))) +(defn ^{:doc "Time between temporal entities `o` and `e` in unit `u`. + + ``` + (j/time-between (j/local-date 2015) (j/local-date 2016) :days) + => 365 + + (j/time-between :days (j/local-date 2015) (j/local-date 2016)) + => 365 + ```"} time-between ([o e u] (java-time.core/time-between o e u))) +(defn ^{:doc "Returns this temporal entity with the specified `ZoneId`"} with-zone ([o z] (java-time.core/with-zone o z))) +(def ^{:arglists (quote ([o & os])), :doc "Adds all of the `os` to the time entity `o`. `plus` is not commutative, the + first argument is always the entity which will accumulate the rest of the + arguments. + + ``` + (j/plus (j/local-date 2015) (j/years 1)) + => + ```"} plus java-time.core/plus) +(def ^{:arglists (quote ([o & os])), :doc "Subtracts all of the `os` from the time entity `o` + + ``` + (j/minus (j/local-date 2015) (j/years 1)) + => + ```"} minus java-time.core/minus) +(defn ^{:doc "Entity `o` multiplied by the value `v`"} multiply-by ([o v] (java-time.core/multiply-by o v))) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. + + ``` + (j/< (local-date 2009) (local-date 2010) (local-date 2011)) + => true + + (j/< (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```"} < java-time.core/<) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. + + ``` + (j/> (local-date 2011) (local-date 2010) (local-date 2009)) + => true + + (j/> (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```"} > java-time.core/>) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (j/<= (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (j/<= (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```"} <= java-time.core/<=) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (j/>= (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (j/>= (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```"} >= java-time.core/>=) +(def ^{:arglists (quote ([o v])), :doc "Entity `o` multiplied by the value `v`"} * java-time.core/*) +(def ^{:arglists (quote ([o & os])), :doc "Subtracts all of the `os` from the time entity `o` + + ``` + (j/- (j/local-date 2015) (j/years 1)) + => + ```"} - java-time.core/-) +(def ^{:arglists (quote ([o & os])), :doc "Adds all of the `os` to the time entity `o`. `+` is not commutative, the + first argument is always the entity which will accumulate the rest of the + arguments. + + ``` + (j/+ (j/local-date 2015) (j/years 1)) + => + ```"} + java-time.core/+) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns true if all time entities represent the same time, otherwise false. + + `j/=` is not commutative, the first argument is always the entity which will + accumulate the rest of the arguments. + + e.g., (j/= (j/day-of-week :thursday) :thursday) => true"} = java-time.core/=) +(defn ^{:doc "The `Chronology` of the entity", :tag java.time.chrono.Chronology} chronology ([o] (java-time.core/chronology o))) +(defn ^{:doc "True if the year of this entity is a leap year."} leap? ([o] (java-time.core/leap? o))) +(defn ^{:doc "Underlying temporal entity with the value of this property set to `v`"} with-value ([p v] (java-time.core/with-value p v))) +(defn ^{:doc "Underlying temporal entity with the value set to the minimum available for + this property"} with-min-value ([p] (java-time.core/with-min-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the maximum + available for this property"} with-max-value ([p] (java-time.core/with-max-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the largest minimum + available for this property"} with-largest-min-value ([p] (java-time.core/with-largest-min-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the smallest maximum + available for this property"} with-smallest-max-value ([p] (java-time.core/with-smallest-max-value p))) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates a duration - a temporal entity representing standard days, hours, + minutes, millis, micros and nanos. The duration itself contains only seconds + and nanos as properties. + + Given one argument will: + + * interpret as millis if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period/Duration + + Given two arguments will: + + * get a duration between two `Temporal`s + * get a duration of a specified unit, e.g. `(duration 100 :seconds)`", :tag java.time.Duration} duration java-time.amount/duration) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a period - a temporal entity consisting of years, months and days. + + Given one argument will + + * interpret as years if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period + + Given two arguments will + + * get a period of a specified unit, e.g. `(period 10 :months)` + * get a period between two temporals by converting them to local dates + * get a period of a specified number of years and months + + Given three arguments will create a year/month/day period.", :tag java.time.Period} period java-time.amount/period) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Period, otherwise false."} period? java-time.amount/period?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Duration, otherwise false."} duration? java-time.amount/duration?) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` nanos.", :tag java.time.Duration} nanos java-time.amount/nanos) +(def ^{:arglists (quote ([micros])), :doc "Duration of a specified number of microseconds.", :tag java.time.Duration} micros java-time.amount/micros) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` millis.", :tag java.time.Duration} millis java-time.amount/millis) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` seconds.", :tag java.time.Duration} seconds java-time.amount/seconds) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` minutes.", :tag java.time.Duration} minutes java-time.amount/minutes) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` hours.", :tag java.time.Duration} hours java-time.amount/hours) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` days.", :tag java.time.Duration} standard-days java-time.amount/standard-days) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` days.", :tag java.time.Period} days java-time.amount/days) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` weeks.", :tag java.time.Period} weeks java-time.amount/weeks) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` months.", :tag java.time.Period} months java-time.amount/months) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` years.", :tag java.time.Period} years java-time.amount/years) +(def ^{:arglists (quote ([o])), :doc "True if this is a `TemporalUnit`."} unit? java-time.properties/unit?) +(def ^{:arglists (quote ([k] [entity k])), :doc "Returns a `TemporalUnit` for the given key `k` or extracts the field from + the given temporal `entity`. + + You can see predefined units via [[java-time.repl/show-units]]. + + If you want to make your own custom TemporalUnits resolvable, you need to rebind the + `java-time.properties/*units*` to a custom `java_time.properties.UnitGroup`.", :tag java.time.temporal.TemporalUnit} unit java-time.properties/unit) +(def ^{:arglists (quote ([o])), :doc "True if this is a `TemporalField`."} field? java-time.properties/field?) +(def ^{:arglists (quote ([k] [entity k])), :doc "Returns a `TemporalField` for the given key `k` or extracts the field from + the given temporal `entity`. + + You can see predefined fields via [[java-time.repl/show-fields]]. + + If you want to make your own custom TemporalFields resolvable, you need to rebind the + `java-time.properties/*fields*` to a custom `java_time.properties.FieldGroup`.", :tag java.time.temporal.TemporalUnit} field java-time.properties/field) +(def ^{:arglists (quote ([min max] [arg0])), :doc "Creates a `ValueRange` given the `min` and `max` amounts or a map of + `:min-smallest`, `:max-smallest`, `:min-largest` and `:max-largest`.", :tag java.time.temporal.ValueRange} value-range java-time.temporal/value-range) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates an `Instant`. The following arguments are supported: + + * no arguments - current instant + * one argument + + clock + + java.util.Date/Calendar + + another temporal entity + + string representation + + millis from epoch + * two arguments + + formatter (format) and a string", :tag java.time.Instant} instant java-time.temporal/instant) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Instant, otherwise false."} instant? java-time.temporal/instant?) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalDate`. The following arguments are supported: + + * no arguments - current local-date + * one argument + + clock + + another temporal entity + + string representation + + year + * two arguments + + formatter (format) and a string + + an instant and a zone id + + another temporal entity and an offset (preserves local time) + + year and month + * three arguments + + year, month and date", :tag java.time.LocalDate} local-date java-time.local/local-date) +(def ^{:arglists (quote ([] [y m d h] [y m d h mm] [y m d h mm ss] [y m d h mm ss n] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalDateTime`. The following arguments are supported: + + * no arguments - current local date-time + * one argument + + clock + + another temporal entity + + string representation + + year + * two arguments + + local date and local time + + an instant and a zone id + + formatter (format) and a string + + year and month + + * three and more arguments - year/month/day/...", :tag java.time.LocalDateTime} local-date-time java-time.local/local-date-time) +(def ^{:arglists (quote ([] [h m s nn] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalTime`. The following arguments are supported: + + * no arguments - current local time + * one argument + + clock + + another temporal entity + + string representation + + hours + * two arguments + + formatter (format) and a string + + an instant and a zone id + + hours and minutes + * three/four arguments - hour, minute, second, nanos", :tag java.time.LocalTime} local-time java-time.local/local-time) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalDate, otherwise false."} local-date? java-time.local/local-date?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalDateTime, otherwise false."} local-date-time? java-time.local/local-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalTime, otherwise false."} local-time? java-time.local/local-time?) +(def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `Year` for the given entity, string, clock, zone or number. + Current year if no arguments given.", :tag java.time.Year} year java-time.single-field/year) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.Year`, otherwise false."} year? java-time.single-field/year?) +(def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `Month` for the given month keyword name (e.g. `:january`), + ordinal or entity. Current month if no arguments given.", :tag java.time.Month} month java-time.single-field/month) +(def ^{:arglists (quote ([o])), :doc "True if `java.time.Month`."} month? java-time.single-field/month?) +(def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `DayOfWeek` for the given day keyword name (e.g. `:monday`), + ordinal or entity. Current day if no arguments given.", :tag java.time.DayOfWeek} day-of-week java-time.single-field/day-of-week) +(def ^{:arglists (quote ([o])), :doc "True if `java.time.DayOfWeek`."} day-of-week? java-time.single-field/day-of-week?) +(def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `MonthDay` for the given entity, string, clock, zone or + month/day combination. Current month-day if no arguments given.", :tag java.time.MonthDay} month-day java-time.single-field/month-day) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.MonthDay`, otherwise false."} month-day? java-time.single-field/month-day?) +(def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `YearMonth` for the given entity, string, clock, zone or + month/day combination. Current year-month if no arguments given.", :tag java.time.YearMonth} year-month java-time.single-field/year-month) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.YearMonth`, otherwise false."} year-month? java-time.single-field/year-month?) +(def ^{:arglists (quote ([])), :doc "Returns a set of string identifiers for all available ZoneIds."} available-zone-ids java-time.zone/available-zone-ids) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates a `ZoneId` from a string identifier, `java.util.TimeZone` or extracts + from another temporal entity. + + Returns default system zone id if no arguments provided. + + Given two arguments will use the second as the offset.", :tag java.time.ZoneId} zone-id java-time.zone/zone-id) +(def ^{:arglists (quote ([] [o] [h m] [h m s])), :doc "Creates a `ZoneOffset` from a string identifier (e.g. \"+01\"), a number of + hours/hours and minutes/hours, minutes and seconds or extracts from another + temporal entity. + + Returns default system zone offset if no arguments provided.", :tag java.time.ZoneOffset} zone-offset java-time.zone/zone-offset) +(def ^{:arglists (quote ([] [y m d h] [y mo d h m] [y mo d h m s] [y mo d h m s n] [y mo d h m s n o] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates an `OffsetDateTime`. The following arguments are supported: + + * no arguments - current date-time with the default offset + * one argument + + clock + + zone offset + + another temporal entity + + string representation + + year + * two arguments + + formatter (format) and a string + + local date-time and an offset + + another temporal entity and an offset (preserves local time) + + year and month + * three arguments + + local date, local time and an offset + + year, month and date + * four up to seven arguments - position date-time constructors + * eight arguments - time fields up to nanoseconds and a zone offset + + If zone offset is not specified, default will be used. You can check the + default offset by invoking `(zone-offset)`.", :tag java.time.OffsetDateTime} offset-date-time java-time.zone/offset-date-time) +(def ^{:arglists (quote ([] [h m s] [h m s n] [h m s n o] [arg0] [arg0 arg1])), :doc "Creates an `OffsetTime`. The following arguments are supported: + + * no arguments - current time with the default offset + * one argument + + clock + + zone id + + another temporal entity + + string representation + + hour + * two arguments + + formatter (format) and a string + + local time and an offset + + instant and an offset + + hour and minutes + * three arguments - hours, minutes, seconds + * four arguments - hours, minutes, seconds, nanos + * five arguments - last is the offset + + If zone offset is not specified, default will be used. You can check the + default offset by invoking `(zone-offset)`.", :tag java.time.OffsetTime} offset-time java-time.zone/offset-time) +(def ^{:arglists (quote ([] [y m d h] [y mo d h m] [y mo d h m s] [y mo d h m s n] [y mo d h m s n o] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `ZonedDateTime`. The following arguments are supported: + + * no arguments - current date-time in the default zone + * one argument + + clock + + zone id + + another temporal entity + + string representation + + year + * two arguments + + formatter and a string + + local date-time and a zone id + + year and month + * three arguments + + local date, local time and a zone id + + year, month and day + * four to seven arguments - date-time fields + * eight arguments - last is the zone id + + If zone id is not specified, default zone id will be used. You can check the + default zone by invoking `(zone-id)`.", :tag java.time.ZonedDateTime} zoned-date-time java-time.zone/zoned-date-time) +(def ^{:arglists (quote ([] [k])), :doc "Creates a system clock. In the default time zone if called without arguments, + otherwise accepts a Zone Id.", :tag java.time.Clock} system-clock java-time.zone/system-clock) +(def ^{:arglists (quote ([] [i] [i z])), :doc "Creates a fixed clock either at the current instant or at the supplied + instant/instant + zone.", :tag java.time.Clock} fixed-clock java-time.zone/fixed-clock) +(def ^{:arglists (quote ([d] [^Clock c d])), :doc "Creates a clock offset from the current/provided clock by a given + `duration`.", :tag java.time.Clock} offset-clock java-time.zone/offset-clock) +(def ^{:arglists (quote ([d] [^Clock c d])), :doc "Creates a clock wrapping system/provided clock that only ticks as per + specified duration.", :tag java.time.Clock} tick-clock java-time.zone/tick-clock) +(def ^{:arglists (quote ([x])), :doc "Returns true if `x` is an instance of `java.time.Clock`."} clock? java-time.zone/clock?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.ZoneId, otherwise false."} zone-id? java-time.zone/zone-id?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.ZonedDateTime, otherwise false."} zoned-date-time? java-time.zone/zoned-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.OffsetDateTime, otherwise false."} offset-date-time? java-time.zone/offset-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.OffsetTime, otherwise false."} offset-time? java-time.zone/offset-time?) +(def ^{:arglists (quote ([^ZonedDateTime zdt z])), :doc "Sets the zone to the specified value ensuring that the result has the same instant, e.g.: + + (zoned-date-time 2015) + => # + (with-zone-same-instant *1 \"America/New_York\") + => #"} with-zone-same-instant java-time.zone/with-zone-same-instant) +(defn ^{:doc "Sets the offset to the specified value ensuring that the local time stays + the same. + + (offset-time 10 30 0 0 +2) + => # + (with-offset *1 +3) + => #"} with-offset ([o offset] (java-time.zone/with-offset o offset))) +(defn ^{:doc "Sets the offset to the specified value ensuring that the result has the same instant, e.g.: + + (offset-time 10 30 0 0 +2) + => # + (with-offset-same-instant *1 +3) + => #"} with-offset-same-instant ([o offset] (java-time.zone/with-offset-same-instant o offset))) +(def ^{:arglists (quote ([] [instant] [instant zone])), :doc "Returns a mock implementation of the `java.time.Clock`. The mock supports + `advance-clock!` operation which allows to move the time in the clock, e.g.: + + ``` + (let [clock (mock-clock 0 \"UTC\")] + (with-clock clock + (is (= (value clock) 0)) + (is (= (instant) (instant 0))) + (advance-clock! clock (j/millis 1)) + (is (= (value clock) 1)) + (is (= (instant) (instant 1))))) + ``` + + You can move the clock back via advancing by a negative temporal amount. + + Creates a clock at epoch in the default time zone when called without arguments.", :tag java.time.Clock} mock-clock java-time.mock/mock-clock) +(def ^{:arglists (quote ([^IMockClock clock amount])), :doc "Advances the `clock` by the given time `amount`. + + This mutates the mock clock."} advance-clock! java-time.mock/advance-clock!) +(def ^{:arglists (quote ([^Clock clock time])), :doc "Sets the `clock` to the given `time`. + + This mutates the mock clock."} set-clock! java-time.mock/set-clock!) +(def ^{:arglists (quote ([e] [e value-fn])), :doc "Converts a time entity to a map of property key -> value as defined by the + passed in `value-fn`. By default the actual value of the unit/field is + produced. + + ``` + (as-map (duration)) + => {:nanos 0, :seconds 0} + + (as-map (local-date 2015 1 1)) + => {:year 2015, :month-of-year 1, :day-of-month 1, ...} + ```"} as-map java-time.convert/as-map) +(def ^{:arglists (quote ([amount from-unit to-unit])), :doc "Converts an amount from one unit to another. Returns a map of: + + * `:whole` - the whole part of the conversion in the `to` unit + * `:remainder` - the remainder in the `from` unit + + Arguments may be keywords or instances of `TemporalUnit`. + + Converts between precise units--nanos up to weeks---treating days as exact + multiples of 24 hours. Also converts between imprecise units---months up to + millennia. See `ChronoUnit` and `IsoFields` for all of the supported units. + Does not convert between precise and imprecise units. + + Throws `ArithmeticException` if long overflow occurs during computation. + + ``` + (convert-amount 10000 :seconds :hours) + => {:remainder 2800 :whole 2} + ```"} convert-amount java-time.convert/convert-amount) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a date entity to a `java.util.Date`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.Instant`. Please consider using [[java-date]] + instead.", :tag java.util.Date} to-java-date java-time.convert/to-java-date) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a local date entity to a `java.sql.Date`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.LocalDate`. Please consider using [[sql-date]] + instead.", :tag java.sql.Date} to-sql-date java-time.convert/to-sql-date) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a date entity to a `java.sql.Timestamp`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.Instant`. Please consider using [[sql-timestamp]] + instead.", :tag java.sql.Timestamp} to-sql-timestamp java-time.convert/to-sql-timestamp) +(def ^{:arglists (quote ([o])), :doc "Converts a date entity to a `long` representing the number of milliseconds + from epoch."} to-millis-from-epoch java-time.convert/to-millis-from-epoch) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Monday, otherwise false."} monday? java-time.sugar/monday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Tuesday, otherwise false."} tuesday? java-time.sugar/tuesday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Wednesday, otherwise false."} wednesday? java-time.sugar/wednesday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Thursday, otherwise false."} thursday? java-time.sugar/thursday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Friday, otherwise false."} friday? java-time.sugar/friday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Saturday, otherwise false."} saturday? java-time.sugar/saturday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Sunday, otherwise false."} sunday? java-time.sugar/sunday?) +(def ^{:arglists (quote ([dt])), :doc "Returns true if argument is [[saturday?]] or [[sunday?]], + otherwise false."} weekend? java-time.sugar/weekend?) +(def ^{:arglists (quote ([dt])), :doc "Complement of [[weekend?]]."} weekday? java-time.sugar/weekday?) +(def ^{:arglists (quote ([f initial v & vs])), :doc "Returns a lazy sequence of `initial` , `(apply f initial v vs)`, etc. + + Useful when you want to produce a sequence of temporal entities, for + example: + + ``` + (iterate plus (days 0) 1) + => (# # # ...) + + (iterate plus (local-date 2010 1 1) (years 1)) + => (# # ...) + + (iterate adjust (local-date 2010 1 1) :next-working-day) + => (# # ...) + ```"} iterate java-time.seqs/iterate) +(def ^{:arglists (quote ([entity adjuster & args])), :doc "Adjusts the temporal `entity` using the provided `adjuster` with optional `args`. + + The adjuster should either be a keyword which resolves to one of the + predefined adjusters (see [[java-time.repl/show-adjusters]]) an instance of + `TemporalAdjuster` or a function which returns another temporal entity when + applied to the given one: + + ``` + (adjust (local-date 2015 1 1) :next-working-day) + => # + + (adjust (local-date 2015 1 1) :first-in-month :monday) + => # + + (adjust (local-date 2015 1 1) plus (days 1)) + => # + ```"} adjust java-time.adjuster/adjust) +(def ^{:arglists (quote ([o] [fmt o])), :doc "Formats the given time entity as a string. + + Accepts something that can be converted to a `DateTimeFormatter` or a + formatter key, e.g. `:iso-offset-time`, as a first argument. Given one + argument uses the default format. + + ``` + (format (zoned-date-time)) + => \"2015-03-21T09:22:46.677800+01:00[Europe/London]\" + + (format :iso-date (zoned-date-time)) + \"2015-03-21+01:00\" + ```"} format java-time.format/format) +(def ^{:arglists (quote ([fmt] [fmt arg1])), :doc "Constructs a DateTimeFormatter out of a + + * format string - \"yyyy/MM/dd\", \"HH:mm\", etc. + * formatter name - :iso-date, :iso-time, etc. + + Accepts a map of options as an optional second argument: + + * `resolver-style` - either `:strict`, `:smart` or `:lenient` + * `case` - either `:insensitive` or `:sensitive` (defaults to :sensitive)", :tag java.time.format.DateTimeFormatter} formatter java-time.format/formatter) +(def ^{:arglists (quote ([] [a] [a b])), :doc "Creates a `java.util.Date` out of any combination of arguments valid for + [[instant]] or the Instant itself. + + A `java.util.Date` represents an instant in time. It's a direct analog of the + `java.time.Instant` type introduced in the JSR-310. Please consider using the + `java.time.Instant` (through [[instant]]) directly.", :tag java.util.Date} java-date java-time.pre-java8/java-date) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `java.sql.Date` out of any combination of arguments valid for + [[local-date]] or the `LocalDate` itself. + + Please consider using the JSR-310 Java Time types instead of `java.sql.Date` + if your drivers support them. + + Even though `java.sql.Date` extends a `java.util.Date`, it's supposed to be + used as a local date (no time component or time zone) for the purposes of + conversion from/to native JDBC driver DATE types.", :tag java.sql.Date} sql-date java-time.pre-java8/sql-date) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2] [arg0 arg1 arg2 arg3] [arg0 arg1 arg2 arg3 arg4] [arg0 arg1 arg2 arg3 arg4 arg5] [arg0 arg1 arg2 arg3 arg4 arg5 arg6])), :doc "Creates a `java.sql.Timestamp` in the local time zone out of any combination + of arguments valid for [[local-date-time]] or the `LocalDateTime` + itself. + + Does not support `Timestamp` construction from an `Instant` or a long millis value---please use + [[instant->sql-timestamp]] for this purpose. + + Please consider using the JSR-310 Java Time types instead of + `java.sql.Timestamp` if your drivers support them. + + `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used + as a local date-time (no time zone) for the purposes of conversion from/to native + JDBC driver TIMESTAMP types.", :tag java.sql.Timestamp} sql-timestamp java-time.pre-java8/sql-timestamp) +(def ^{:arglists (quote ([instant-or-millis])), :doc "Creates a `java.sql.Timestamp` from the provided `instant-or-millis` - a + millisecond numeric time value or something convertible to an `Instant`. + + Please consider using the JSR-310 Java Time types instead of + `java.sql.Timestamp` if your drivers support them. + + `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used + as a local date-time (no time zone) for the purposes of conversion from/to native + JDBC driver TIMESTAMP types."} instant->sql-timestamp java-time.pre-java8/instant->sql-timestamp) +(java-time.util/when-class "java.sql.Time" (def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `java.sql.Time` out of any combination of arguments valid for + [[local-time]] (except the nanos constructor) or the `LocalTime` + itself. + + Please consider using the JSR-310 Java Time types instead of `java.sql.Time` + if your drivers support them. + + Even though `java.sql.Time` extends a `java.util.Date`, it's supposed to be + used as a local time (no date component or time zone) for the purposes of + conversion from/to native JDBC driver TIME types.", :tag java.sql.Time} sql-time java-time.pre-java8/sql-time)) +(defn ^{:doc "Moves the start instant of the interval to the given instant (or something + convertible to an instant): + + ``` + (move-start-to (interval 0 10000) (instant 5000)) + => # + ``` + + Fails if the new start instant falls after the end instant: + + ``` + (move-start-to (interval 0 10000) (millis 15000)) + => DateTimeException... + ```"} move-start-to ([i new-start] (java-time.interval/move-start-to i new-start))) +(defn ^{:doc "Moves the end of the interval to the given instant (or something + convertible to an instant): + + ``` + (move-end-to (interval 0 10000) (instant 15000)) + => # + ``` + + Fails if the new end instant falls before the start instant: + + ``` + (move-end-to (interval 0 10000) (millis -1)) + => DateTimeException... + ```"} move-end-to ([i new-end] (java-time.interval/move-end-to i new-end))) +(def ^{:arglists (quote ([i & os])), :doc "Moves the start instant of the interval by the sum of given + periods/durations/numbers of milliseconds: + + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` + + Fails if the new start instant falls after the end instant. + + ``` + (move-start-by (interval 0 10000) (millis 11000)) + ;=> DateTimeException... + ```"} move-start-by java-time.interval/move-start-by) +(def ^{:arglists (quote ([i & os])), :doc "Moves the end instant of the interval by the sum of given + periods/durations/numbers of milliseconds. + + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` + + Fails if the new end instant falls before the start instant. + + ``` + (move-end-by (interval 0 10000) (millis -11000)) + => DateTimeException... + ```"} move-end-by java-time.interval/move-end-by) +(defn ^{:doc "Gets the start instant of the interval"} start ([i] (java-time.interval/start i))) +(defn ^{:doc "Gets the end instant of the interval"} end ([i] (java-time.interval/end i))) +(defn ^{:doc "True if the interval contains the given instant or interval"} contains? ([i o] (java-time.interval/contains? i o))) +(defn ^{:doc "True if this interval overlaps the other one"} overlaps? ([i oi] (java-time.interval/overlaps? i oi))) +(defn ^{:doc "True if this interval abut with the other one"} abuts? ([i oi] (java-time.interval/abuts? i oi))) +(defn ^{:doc "Gets the overlap between this interval and the other one or `nil`"} overlap ([i oi] (java-time.interval/overlap i oi))) +(defn ^{:doc "Gets the gap between this interval and the other one or `nil`"} gap ([i oi] (java-time.interval/gap i oi))) +(java-time.util/when-class "org.threeten.extra.Temporals" (def ^{:arglists (quote ([^String o] [a b])), :doc "Constructs an interval out of a string, start and end instants or a start + + duration: + + ``` + (j/interval \"2010-01-01T00:00:00Z/2013-01-01T00:00:00Z\") + => # + + (j/interval (j/instant 100000) (j/instant 1000000)) + => # + + (j/interval (j/instant 100000) (j/duration 15 :minutes)) + => # + ``` + + Requires the optional `threeten-extra` dependency.", :tag org.threeten.extra.Interval} interval java-time.interval/interval) (def ^{:arglists (quote ([o])), :doc "True if `Interval`"} interval? java-time.interval/interval?) (def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `AmPm` for the given keyword name (`:am` or `:pm`), + ordinal or entity. Current AM/PM if no arguments given.", :tag org.threeten.extra.AmPm} am-pm java-time.single-field/am-pm) (def ^{:arglists (quote ([o])), :doc "True if `org.threeten.extra.AmPm`."} am-pm? java-time.single-field/am-pm?) (def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `Quarter` for the given quarter keyword name (e.g. `:q1`), + ordinal or entity. Current quarter if no arguments given.", :tag org.threeten.extra.Quarter} quarter java-time.single-field/quarter) (def ^{:arglists (quote ([o])), :doc "True if `org.threeten.extra.Quarter`."} quarter? java-time.single-field/quarter?) (def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `DayOfMonth` for the given entity, clock, zone or day of month. + Current day of month if no arguments given.", :tag org.threeten.extra.DayOfMonth} day-of-month java-time.single-field/day-of-month) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.DayOfMonth`, otherwise false."} day-of-month? java-time.single-field/day-of-month?) (def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `DayOfYear` for the given entity, clock, zone or day of year. + Current day of year if no arguments given.", :tag org.threeten.extra.DayOfYear} day-of-year java-time.single-field/day-of-year) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.DayOfYear`, otherwise false."} day-of-year? java-time.single-field/day-of-year?) (def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `YearQuarter` for the given entity, clock, zone or year with quarter. + Current year quarter if no arguments given.", :tag org.threeten.extra.YearQuarter} year-quarter java-time.single-field/year-quarter) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.YearQuarter`, otherwise false."} year-quarter? java-time.single-field/year-quarter?)) diff --git a/src/java_time/adjuster.clj b/src/java_time/adjuster.clj index 1369fd4..a486d54 100644 --- a/src/java_time/adjuster.clj +++ b/src/java_time/adjuster.clj @@ -1,7 +1,7 @@ (ns java-time.adjuster (:require [java-time.util :as jt.u] [java-time.single-field :as jt.sf]) - (:import [java.time.temporal TemporalAdjusters TemporalAdjuster])) + (:import [java.time.temporal Temporal TemporalAdjusters TemporalAdjuster])) (def base-adjusters {:first-day-of-month [(TemporalAdjusters/firstDayOfMonth) 0] :last-day-of-month [(TemporalAdjusters/lastDayOfMonth) 0] @@ -41,18 +41,20 @@ "Adjusts the temporal `entity` using the provided `adjuster` with optional `args`. The adjuster should either be a keyword which resolves to one of the - predefined adjusters (see `java-time.repl/show-adjusters`) an instance of + predefined adjusters (see [[java-time.repl/show-adjusters]]) an instance of `TemporalAdjuster` or a function which returns another temporal entity when applied to the given one: - (adjust (local-date 2015 1 1) :next-working-day) - => # + ``` + (adjust (local-date 2015 1 1) :next-working-day) + => # - (adjust (local-date 2015 1 1) :first-in-month :monday) - => # + (adjust (local-date 2015 1 1) :first-in-month :monday) + => # - (adjust (local-date 2015 1 1) plus (days 1)) - => #" + (adjust (local-date 2015 1 1) plus (days 1)) + => # + ```" [entity adjuster & args] (cond (instance? TemporalAdjuster adjuster) (.adjustInto ^TemporalAdjuster adjuster ^Temporal entity) diff --git a/src/java_time/amount.clj b/src/java_time/amount.clj index 829dad4..2cd29a2 100644 --- a/src/java_time/amount.clj +++ b/src/java_time/amount.clj @@ -52,20 +52,22 @@ minutes, millis, micros and nanos. The duration itself contains only seconds and nanos as properties. - Given one argument will - * interpret as millis if a number - * try to parse from the standard format if a string - * extract supported units from another `TemporalAmount` - * convert from a Joda Period/Duration + Given one argument will: - Given two arguments will - * get a duration between two `Temporal`s - * get a duration of a specified unit, e.g. `(duration 100 :seconds)`" + * interpret as millis if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period/Duration + + Given two arguments will: + + * get a duration between two `Temporal`s + * get a duration of a specified unit, e.g. `(duration 100 :seconds)`" :returns Duration :implicit-arities [1 2] ([] (Duration/ofMillis 0))) -(defn ^Duration micros +(defn ^java.time.Duration micros "Duration of a specified number of microseconds." [micros] (Duration/ofNanos (Math/multiplyExact (long micros) 1000))) @@ -75,9 +77,10 @@ (conj (map (fn [[fn-name method-name]] (let [fn-name (with-meta fn-name {:tag Duration})] `(defn ~fn-name - ~(str "Duration of a specified number of " method-name ".") - [v#] - (. Duration ~(symbol (str 'of (string/capitalize (str method-name)))) (long v#))))) + ~(str "Returns a `Duration` of `i` " method-name ".") + {:arglists '[[~'i]]} + [i#] + (. Duration ~(symbol (str 'of (string/capitalize (str method-name)))) (long i#))))) [['standard-days 'days] ['hours 'hours] ['minutes 'minutes] @@ -93,8 +96,10 @@ (conj (map (fn [fn-name] (let [fn-name (with-meta fn-name {:tag Period})] `(defn ~fn-name - [v#] - (. Period ~(symbol (str 'of (string/capitalize (str fn-name)))) (int v#))))) + ~(str "Returns a `Period` of `i` " fn-name ".") + {:arglists '[[~'i]]} + [i#] + (. Period ~(symbol (str 'of (string/capitalize (str fn-name)))) (int i#))))) ['years 'months 'days @@ -107,15 +112,17 @@ "Creates a period - a temporal entity consisting of years, months and days. Given one argument will - * interpret as years if a number - * try to parse from the standard format if a string - * extract supported units from another `TemporalAmount` - * convert from a Joda Period + + * interpret as years if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period Given two arguments will - * get a period of a specified unit, e.g. `(period 10 :months)` - * get a period between two temporals by converting them to local dates - * get a period of a specified number of years and months + + * get a period of a specified unit, e.g. `(period 10 :months)` + * get a period between two temporals by converting them to local dates + * get a period of a specified number of years and months Given three arguments will create a year/month/day period." :returns Period diff --git a/src/java_time/api.clj b/src/java_time/api.clj new file mode 100644 index 0000000..549cd14 --- /dev/null +++ b/src/java_time/api.clj @@ -0,0 +1,711 @@ +;; NOTE: This namespace is generated by java-time.dev.gen +(ns ^{:supercedes "java-time"} java-time.api (:refer-clojure :exclude (zero? range iterate max min contains? format abs < > <= >= = * - + neg?)) (:require [java-time core properties temporal amount zone single-field local chrono convert sugar seqs adjuster interval format joda clock pre-java8 mock])) +(defmacro ^{:doc "Executes the given `forms` in the scope of the provided `clock`. + + All the temporal entities that get created without parameters will inherit + their values from the clock: + + (with-clock (system-clock \"Europe/London\") + (zone-id)) + => #"} with-clock [c & forms] (list* (quote java-time.clock/with-clock) c forms)) +(defmacro ^{:doc "Execute the `body` when Joda-Time classes are found on the classpath. + + Take care - when AOT-compiling code using this macro, the Joda-Time classes + must be on the classpath at compile time!"} when-joda-time-loaded [& body] (list* (quote java-time.util/when-joda-time-loaded) body)) +(def ^{:arglists (quote ([^Clock c f])), :doc "Executes the given function in the scope of the provided clock. All the + temporal entities that get created without parameters will inherit their + values from the clock."} with-clock-fn java-time.clock/with-clock-fn) +(defn ^{:doc "True if the amount is zero"} zero? ([a] (java-time.core/zero? a))) +(defn ^{:doc "True if the amount is negative"} negative? ([a] (java-time.core/negative? a))) +(defn ^{:doc "Negates a temporal amount: + + (negate (negate x)) == x"} negate ([a] (java-time.core/negate a))) +(defn ^{:doc "Returns the absolute value of a temporal amount: + + (abs (negate x)) == (abs x)"} abs ([a] (java-time.core/abs a))) +(def ^{:arglists (quote ([o & os])), :doc "Latest/longest of the given time entities. Entities should be of the same + type"} max java-time.core/max) +(def ^{:arglists (quote ([o & os])), :doc "Earliest/shortest of the given time entities. Entities should be of the same + type"} min java-time.core/min) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. + + ``` + (before? (local-date 2009) (local-date 2010) (local-date 2011)) + => true + + (before? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```"} before? java-time.core/before?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (not-after? (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (not-after? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```"} not-after? java-time.core/not-after?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. + + ``` + (after? (local-date 2011) (local-date 2010) (local-date 2009)) + => true + + (after? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```"} after? java-time.core/after?) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (not-before? (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (not-before? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```"} not-before? java-time.core/not-before?) +(defn ^{:doc "True if the `o` entity supports the `p` property"} supports? ([o p] (java-time.core/supports? o p))) +(defn ^{:doc "Fields present in this temporal entity"} fields ([o] (java-time.core/fields o))) +(defn ^{:doc "Units present in this temporal entity."} units ([o] (java-time.core/units o))) +(defn ^{:doc "Map of properties present in this temporal entity"} properties ([o] (java-time.core/properties o))) +(defn ^{:doc "Property of this temporal entity under key `k`"} property ([o k] (java-time.core/property o k))) +(def ^{:arglists (quote ([o k] [o k1 k2] [o k1 k2 & ks])), :doc "Values of property/unit identified by keys/objects `ks` of the temporal + entity `o`, e.g. + + ``` + (as (duration 1 :hours) :minutes) + => 60 + + (as (local-date 2015 9) :year :month-of-year) + => [2015 9] + ```"} as java-time.core/as) +(defn ^{:doc "Value of the property"} value ([p] (java-time.core/value p))) +(defn ^{:doc "Range of values for this property"} range ([p] (java-time.core/range p))) +(defn ^{:doc "Minimum value of this property"} min-value ([p] (java-time.core/min-value p))) +(defn ^{:doc "Maximum value of this property, e.g. 29th of February for months"} max-value ([p] (java-time.core/max-value p))) +(defn ^{:doc "Largest minimum value of this property"} largest-min-value ([p] (java-time.core/largest-min-value p))) +(defn ^{:doc "Smallest maximum value of this property, e.g. 28th of February for months"} smallest-max-value ([p] (java-time.core/smallest-max-value p))) +(defn ^{:doc "Truncates this entity to the specified time unit. Only works for units that + divide into the length of standard day without remainder (up to `:days`)."} truncate-to ([o u] (java-time.core/truncate-to o u))) +(defn ^{:doc "Time between temporal entities `o` and `e` in unit `u`. + + ``` + (j/time-between (j/local-date 2015) (j/local-date 2016) :days) + => 365 + + (j/time-between :days (j/local-date 2015) (j/local-date 2016)) + => 365 + ```"} time-between ([o e u] (java-time.core/time-between o e u))) +(defn ^{:doc "Returns this temporal entity with the specified `ZoneId`"} with-zone ([o z] (java-time.core/with-zone o z))) +(def ^{:arglists (quote ([o & os])), :doc "Adds all of the `os` to the time entity `o`. `plus` is not commutative, the + first argument is always the entity which will accumulate the rest of the + arguments. + + ``` + (j/plus (j/local-date 2015) (j/years 1)) + => + ```"} plus java-time.core/plus) +(def ^{:arglists (quote ([o & os])), :doc "Subtracts all of the `os` from the time entity `o` + + ``` + (j/minus (j/local-date 2015) (j/years 1)) + => + ```"} minus java-time.core/minus) +(defn ^{:doc "Entity `o` multiplied by the value `v`"} multiply-by ([o v] (java-time.core/multiply-by o v))) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. + + ``` + (j/< (local-date 2009) (local-date 2010) (local-date 2011)) + => true + + (j/< (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```"} < java-time.core/<) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. + + ``` + (j/> (local-date 2011) (local-date 2010) (local-date 2009)) + => true + + (j/> (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```"} > java-time.core/>) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (j/<= (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (j/<= (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```"} <= java-time.core/<=) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (j/>= (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (j/>= (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```"} >= java-time.core/>=) +(def ^{:arglists (quote ([o v])), :doc "Entity `o` multiplied by the value `v`"} * java-time.core/*) +(def ^{:arglists (quote ([o & os])), :doc "Subtracts all of the `os` from the time entity `o` + + ``` + (j/- (j/local-date 2015) (j/years 1)) + => + ```"} - java-time.core/-) +(def ^{:arglists (quote ([o & os])), :doc "Adds all of the `os` to the time entity `o`. `+` is not commutative, the + first argument is always the entity which will accumulate the rest of the + arguments. + + ``` + (j/+ (j/local-date 2015) (j/years 1)) + => + ```"} + java-time.core/+) +(def ^{:arglists (quote ([x] [x y] [x y & more])), :doc "Returns true if all time entities represent the same time, otherwise false. + + `j/=` is not commutative, the first argument is always the entity which will + accumulate the rest of the arguments. + + e.g., (j/= (j/day-of-week :thursday) :thursday) => true"} = java-time.core/=) +(defn ^{:doc "The `Chronology` of the entity", :tag java.time.chrono.Chronology} chronology ([o] (java-time.core/chronology o))) +(defn ^{:doc "True if the year of this entity is a leap year."} leap? ([o] (java-time.core/leap? o))) +(defn ^{:doc "Underlying temporal entity with the value of this property set to `v`"} with-value ([p v] (java-time.core/with-value p v))) +(defn ^{:doc "Underlying temporal entity with the value set to the minimum available for + this property"} with-min-value ([p] (java-time.core/with-min-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the maximum + available for this property"} with-max-value ([p] (java-time.core/with-max-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the largest minimum + available for this property"} with-largest-min-value ([p] (java-time.core/with-largest-min-value p))) +(defn ^{:doc "Underlying temporal entity with the value set to the smallest maximum + available for this property"} with-smallest-max-value ([p] (java-time.core/with-smallest-max-value p))) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates a duration - a temporal entity representing standard days, hours, + minutes, millis, micros and nanos. The duration itself contains only seconds + and nanos as properties. + + Given one argument will: + + * interpret as millis if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period/Duration + + Given two arguments will: + + * get a duration between two `Temporal`s + * get a duration of a specified unit, e.g. `(duration 100 :seconds)`", :tag java.time.Duration} duration java-time.amount/duration) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a period - a temporal entity consisting of years, months and days. + + Given one argument will + + * interpret as years if a number + * try to parse from the standard format if a string + * extract supported units from another `TemporalAmount` + * convert from a Joda Period + + Given two arguments will + + * get a period of a specified unit, e.g. `(period 10 :months)` + * get a period between two temporals by converting them to local dates + * get a period of a specified number of years and months + + Given three arguments will create a year/month/day period.", :tag java.time.Period} period java-time.amount/period) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Period, otherwise false."} period? java-time.amount/period?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Duration, otherwise false."} duration? java-time.amount/duration?) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` nanos.", :tag java.time.Duration} nanos java-time.amount/nanos) +(def ^{:arglists (quote ([micros])), :doc "Duration of a specified number of microseconds.", :tag java.time.Duration} micros java-time.amount/micros) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` millis.", :tag java.time.Duration} millis java-time.amount/millis) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` seconds.", :tag java.time.Duration} seconds java-time.amount/seconds) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` minutes.", :tag java.time.Duration} minutes java-time.amount/minutes) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` hours.", :tag java.time.Duration} hours java-time.amount/hours) +(def ^{:arglists (quote ([i])), :doc "Returns a `Duration` of `i` days.", :tag java.time.Duration} standard-days java-time.amount/standard-days) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` days.", :tag java.time.Period} days java-time.amount/days) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` weeks.", :tag java.time.Period} weeks java-time.amount/weeks) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` months.", :tag java.time.Period} months java-time.amount/months) +(def ^{:arglists (quote ([i])), :doc "Returns a `Period` of `i` years.", :tag java.time.Period} years java-time.amount/years) +(def ^{:arglists (quote ([o])), :doc "True if this is a `TemporalUnit`."} unit? java-time.properties/unit?) +(def ^{:arglists (quote ([k] [entity k])), :doc "Returns a `TemporalUnit` for the given key `k` or extracts the field from + the given temporal `entity`. + + You can see predefined units via [[java-time.repl/show-units]]. + + If you want to make your own custom TemporalUnits resolvable, you need to rebind the + `java-time.properties/*units*` to a custom `java_time.properties.UnitGroup`.", :tag java.time.temporal.TemporalUnit} unit java-time.properties/unit) +(def ^{:arglists (quote ([o])), :doc "True if this is a `TemporalField`."} field? java-time.properties/field?) +(def ^{:arglists (quote ([k] [entity k])), :doc "Returns a `TemporalField` for the given key `k` or extracts the field from + the given temporal `entity`. + + You can see predefined fields via [[java-time.repl/show-fields]]. + + If you want to make your own custom TemporalFields resolvable, you need to rebind the + `java-time.properties/*fields*` to a custom `java_time.properties.FieldGroup`.", :tag java.time.temporal.TemporalUnit} field java-time.properties/field) +(def ^{:arglists (quote ([min max] [arg0])), :doc "Creates a `ValueRange` given the `min` and `max` amounts or a map of + `:min-smallest`, `:max-smallest`, `:min-largest` and `:max-largest`.", :tag java.time.temporal.ValueRange} value-range java-time.temporal/value-range) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates an `Instant`. The following arguments are supported: + + * no arguments - current instant + * one argument + + clock + + java.util.Date/Calendar + + another temporal entity + + string representation + + millis from epoch + * two arguments + + formatter (format) and a string", :tag java.time.Instant} instant java-time.temporal/instant) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.Instant, otherwise false."} instant? java-time.temporal/instant?) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalDate`. The following arguments are supported: + + * no arguments - current local-date + * one argument + + clock + + another temporal entity + + string representation + + year + * two arguments + + formatter (format) and a string + + an instant and a zone id + + another temporal entity and an offset (preserves local time) + + year and month + * three arguments + + year, month and date", :tag java.time.LocalDate} local-date java-time.local/local-date) +(def ^{:arglists (quote ([] [y m d h] [y m d h mm] [y m d h mm ss] [y m d h mm ss n] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalDateTime`. The following arguments are supported: + + * no arguments - current local date-time + * one argument + + clock + + another temporal entity + + string representation + + year + * two arguments + + local date and local time + + an instant and a zone id + + formatter (format) and a string + + year and month + + * three and more arguments - year/month/day/...", :tag java.time.LocalDateTime} local-date-time java-time.local/local-date-time) +(def ^{:arglists (quote ([] [h m s nn] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `LocalTime`. The following arguments are supported: + + * no arguments - current local time + * one argument + + clock + + another temporal entity + + string representation + + hours + * two arguments + + formatter (format) and a string + + an instant and a zone id + + hours and minutes + * three/four arguments - hour, minute, second, nanos", :tag java.time.LocalTime} local-time java-time.local/local-time) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalDate, otherwise false."} local-date? java-time.local/local-date?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalDateTime, otherwise false."} local-date-time? java-time.local/local-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.LocalTime, otherwise false."} local-time? java-time.local/local-time?) +(def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `Year` for the given entity, string, clock, zone or number. + Current year if no arguments given.", :tag java.time.Year} year java-time.single-field/year) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.Year`, otherwise false."} year? java-time.single-field/year?) +(def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `Month` for the given month keyword name (e.g. `:january`), + ordinal or entity. Current month if no arguments given.", :tag java.time.Month} month java-time.single-field/month) +(def ^{:arglists (quote ([o])), :doc "True if `java.time.Month`."} month? java-time.single-field/month?) +(def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `DayOfWeek` for the given day keyword name (e.g. `:monday`), + ordinal or entity. Current day if no arguments given.", :tag java.time.DayOfWeek} day-of-week java-time.single-field/day-of-week) +(def ^{:arglists (quote ([o])), :doc "True if `java.time.DayOfWeek`."} day-of-week? java-time.single-field/day-of-week?) +(def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `MonthDay` for the given entity, string, clock, zone or + month/day combination. Current month-day if no arguments given.", :tag java.time.MonthDay} month-day java-time.single-field/month-day) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.MonthDay`, otherwise false."} month-day? java-time.single-field/month-day?) +(def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `YearMonth` for the given entity, string, clock, zone or + month/day combination. Current year-month if no arguments given.", :tag java.time.YearMonth} year-month java-time.single-field/year-month) +(def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `java.time.YearMonth`, otherwise false."} year-month? java-time.single-field/year-month?) +(def ^{:arglists (quote ([])), :doc "Returns a set of string identifiers for all available ZoneIds."} available-zone-ids java-time.zone/available-zone-ids) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1])), :doc "Creates a `ZoneId` from a string identifier, `java.util.TimeZone` or extracts + from another temporal entity. + + Returns default system zone id if no arguments provided. + + Given two arguments will use the second as the offset.", :tag java.time.ZoneId} zone-id java-time.zone/zone-id) +(def ^{:arglists (quote ([] [o] [h m] [h m s])), :doc "Creates a `ZoneOffset` from a string identifier (e.g. \"+01\"), a number of + hours/hours and minutes/hours, minutes and seconds or extracts from another + temporal entity. + + Returns default system zone offset if no arguments provided.", :tag java.time.ZoneOffset} zone-offset java-time.zone/zone-offset) +(def ^{:arglists (quote ([] [y m d h] [y mo d h m] [y mo d h m s] [y mo d h m s n] [y mo d h m s n o] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates an `OffsetDateTime`. The following arguments are supported: + + * no arguments - current date-time with the default offset + * one argument + + clock + + zone offset + + another temporal entity + + string representation + + year + * two arguments + + formatter (format) and a string + + local date-time and an offset + + another temporal entity and an offset (preserves local time) + + year and month + * three arguments + + local date, local time and an offset + + year, month and date + * four up to seven arguments - position date-time constructors + * eight arguments - time fields up to nanoseconds and a zone offset + + If zone offset is not specified, default will be used. You can check the + default offset by invoking `(zone-offset)`.", :tag java.time.OffsetDateTime} offset-date-time java-time.zone/offset-date-time) +(def ^{:arglists (quote ([] [h m s] [h m s n] [h m s n o] [arg0] [arg0 arg1])), :doc "Creates an `OffsetTime`. The following arguments are supported: + + * no arguments - current time with the default offset + * one argument + + clock + + zone id + + another temporal entity + + string representation + + hour + * two arguments + + formatter (format) and a string + + local time and an offset + + instant and an offset + + hour and minutes + * three arguments - hours, minutes, seconds + * four arguments - hours, minutes, seconds, nanos + * five arguments - last is the offset + + If zone offset is not specified, default will be used. You can check the + default offset by invoking `(zone-offset)`.", :tag java.time.OffsetTime} offset-time java-time.zone/offset-time) +(def ^{:arglists (quote ([] [y m d h] [y mo d h m] [y mo d h m s] [y mo d h m s n] [y mo d h m s n o] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `ZonedDateTime`. The following arguments are supported: + + * no arguments - current date-time in the default zone + * one argument + + clock + + zone id + + another temporal entity + + string representation + + year + * two arguments + + formatter and a string + + local date-time and a zone id + + year and month + * three arguments + + local date, local time and a zone id + + year, month and day + * four to seven arguments - date-time fields + * eight arguments - last is the zone id + + If zone id is not specified, default zone id will be used. You can check the + default zone by invoking `(zone-id)`.", :tag java.time.ZonedDateTime} zoned-date-time java-time.zone/zoned-date-time) +(def ^{:arglists (quote ([] [k])), :doc "Creates a system clock. In the default time zone if called without arguments, + otherwise accepts a Zone Id.", :tag java.time.Clock} system-clock java-time.zone/system-clock) +(def ^{:arglists (quote ([] [i] [i z])), :doc "Creates a fixed clock either at the current instant or at the supplied + instant/instant + zone.", :tag java.time.Clock} fixed-clock java-time.zone/fixed-clock) +(def ^{:arglists (quote ([d] [^Clock c d])), :doc "Creates a clock offset from the current/provided clock by a given + `duration`.", :tag java.time.Clock} offset-clock java-time.zone/offset-clock) +(def ^{:arglists (quote ([d] [^Clock c d])), :doc "Creates a clock wrapping system/provided clock that only ticks as per + specified duration.", :tag java.time.Clock} tick-clock java-time.zone/tick-clock) +(def ^{:arglists (quote ([x])), :doc "Returns true if `x` is an instance of `java.time.Clock`."} clock? java-time.zone/clock?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.ZoneId, otherwise false."} zone-id? java-time.zone/zone-id?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.ZonedDateTime, otherwise false."} zoned-date-time? java-time.zone/zoned-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.OffsetDateTime, otherwise false."} offset-date-time? java-time.zone/offset-date-time?) +(def ^{:arglists (quote ([v])), :doc "Returns true if `v` is an instance of java.time.OffsetTime, otherwise false."} offset-time? java-time.zone/offset-time?) +(def ^{:arglists (quote ([^ZonedDateTime zdt z])), :doc "Sets the zone to the specified value ensuring that the result has the same instant, e.g.: + + (zoned-date-time 2015) + => # + (with-zone-same-instant *1 \"America/New_York\") + => #"} with-zone-same-instant java-time.zone/with-zone-same-instant) +(defn ^{:doc "Sets the offset to the specified value ensuring that the local time stays + the same. + + (offset-time 10 30 0 0 +2) + => # + (with-offset *1 +3) + => #"} with-offset ([o offset] (java-time.zone/with-offset o offset))) +(defn ^{:doc "Sets the offset to the specified value ensuring that the result has the same instant, e.g.: + + (offset-time 10 30 0 0 +2) + => # + (with-offset-same-instant *1 +3) + => #"} with-offset-same-instant ([o offset] (java-time.zone/with-offset-same-instant o offset))) +(def ^{:arglists (quote ([] [instant] [instant zone])), :doc "Returns a mock implementation of the `java.time.Clock`. The mock supports + `advance-clock!` operation which allows to move the time in the clock, e.g.: + + ``` + (let [clock (mock-clock 0 \"UTC\")] + (with-clock clock + (is (= (value clock) 0)) + (is (= (instant) (instant 0))) + (advance-clock! clock (j/millis 1)) + (is (= (value clock) 1)) + (is (= (instant) (instant 1))))) + ``` + + You can move the clock back via advancing by a negative temporal amount. + + Creates a clock at epoch in the default time zone when called without arguments.", :tag java.time.Clock} mock-clock java-time.mock/mock-clock) +(def ^{:arglists (quote ([^IMockClock clock amount])), :doc "Advances the `clock` by the given time `amount`. + + This mutates the mock clock."} advance-clock! java-time.mock/advance-clock!) +(def ^{:arglists (quote ([^Clock clock time])), :doc "Sets the `clock` to the given `time`. + + This mutates the mock clock."} set-clock! java-time.mock/set-clock!) +(def ^{:arglists (quote ([e] [e value-fn])), :doc "Converts a time entity to a map of property key -> value as defined by the + passed in `value-fn`. By default the actual value of the unit/field is + produced. + + ``` + (as-map (duration)) + => {:nanos 0, :seconds 0} + + (as-map (local-date 2015 1 1)) + => {:year 2015, :month-of-year 1, :day-of-month 1, ...} + ```"} as-map java-time.convert/as-map) +(def ^{:arglists (quote ([amount from-unit to-unit])), :doc "Converts an amount from one unit to another. Returns a map of: + + * `:whole` - the whole part of the conversion in the `to` unit + * `:remainder` - the remainder in the `from` unit + + Arguments may be keywords or instances of `TemporalUnit`. + + Converts between precise units--nanos up to weeks---treating days as exact + multiples of 24 hours. Also converts between imprecise units---months up to + millennia. See `ChronoUnit` and `IsoFields` for all of the supported units. + Does not convert between precise and imprecise units. + + Throws `ArithmeticException` if long overflow occurs during computation. + + ``` + (convert-amount 10000 :seconds :hours) + => {:remainder 2800 :whole 2} + ```"} convert-amount java-time.convert/convert-amount) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a date entity to a `java.util.Date`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.Instant`. Please consider using [[java-date]] + instead.", :tag java.util.Date} to-java-date java-time.convert/to-java-date) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a local date entity to a `java.sql.Date`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.LocalDate`. Please consider using [[sql-date]] + instead.", :tag java.sql.Date} to-sql-date java-time.convert/to-sql-date) +(def ^{:arglists (quote ([o])), :deprecated true, :doc "Converts a date entity to a `java.sql.Timestamp`. + + *Deprecated*: + This function only has a single arity and works for entities directly + convertible to `java.time.Instant`. Please consider using [[sql-timestamp]] + instead.", :tag java.sql.Timestamp} to-sql-timestamp java-time.convert/to-sql-timestamp) +(def ^{:arglists (quote ([o])), :doc "Converts a date entity to a `long` representing the number of milliseconds + from epoch."} to-millis-from-epoch java-time.convert/to-millis-from-epoch) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Monday, otherwise false."} monday? java-time.sugar/monday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Tuesday, otherwise false."} tuesday? java-time.sugar/tuesday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Wednesday, otherwise false."} wednesday? java-time.sugar/wednesday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Thursday, otherwise false."} thursday? java-time.sugar/thursday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Friday, otherwise false."} friday? java-time.sugar/friday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Saturday, otherwise false."} saturday? java-time.sugar/saturday?) +(def ^{:arglists (quote ([i])), :doc "Returns true if the given time entity with the + `day-of-week` property falls on a Sunday, otherwise false."} sunday? java-time.sugar/sunday?) +(def ^{:arglists (quote ([dt])), :doc "Returns true if argument is [[saturday?]] or [[sunday?]], + otherwise false."} weekend? java-time.sugar/weekend?) +(def ^{:arglists (quote ([dt])), :doc "Complement of [[weekend?]]."} weekday? java-time.sugar/weekday?) +(def ^{:arglists (quote ([f initial v & vs])), :doc "Returns a lazy sequence of `initial` , `(apply f initial v vs)`, etc. + + Useful when you want to produce a sequence of temporal entities, for + example: + + ``` + (iterate plus (days 0) 1) + => (# # # ...) + + (iterate plus (local-date 2010 1 1) (years 1)) + => (# # ...) + + (iterate adjust (local-date 2010 1 1) :next-working-day) + => (# # ...) + ```"} iterate java-time.seqs/iterate) +(def ^{:arglists (quote ([entity adjuster & args])), :doc "Adjusts the temporal `entity` using the provided `adjuster` with optional `args`. + + The adjuster should either be a keyword which resolves to one of the + predefined adjusters (see [[java-time.repl/show-adjusters]]) an instance of + `TemporalAdjuster` or a function which returns another temporal entity when + applied to the given one: + + ``` + (adjust (local-date 2015 1 1) :next-working-day) + => # + + (adjust (local-date 2015 1 1) :first-in-month :monday) + => # + + (adjust (local-date 2015 1 1) plus (days 1)) + => # + ```"} adjust java-time.adjuster/adjust) +(def ^{:arglists (quote ([o] [fmt o])), :doc "Formats the given time entity as a string. + + Accepts something that can be converted to a `DateTimeFormatter` or a + formatter key, e.g. `:iso-offset-time`, as a first argument. Given one + argument uses the default format. + + ``` + (format (zoned-date-time)) + => \"2015-03-21T09:22:46.677800+01:00[Europe/London]\" + + (format :iso-date (zoned-date-time)) + \"2015-03-21+01:00\" + ```"} format java-time.format/format) +(def ^{:arglists (quote ([fmt] [fmt arg1])), :doc "Constructs a DateTimeFormatter out of a + + * format string - \"yyyy/MM/dd\", \"HH:mm\", etc. + * formatter name - :iso-date, :iso-time, etc. + + Accepts a map of options as an optional second argument: + + * `resolver-style` - either `:strict`, `:smart` or `:lenient` + * `case` - either `:insensitive` or `:sensitive` (defaults to :sensitive)", :tag java.time.format.DateTimeFormatter} formatter java-time.format/formatter) +(def ^{:arglists (quote ([] [a] [a b])), :doc "Creates a `java.util.Date` out of any combination of arguments valid for + [[instant]] or the Instant itself. + + A `java.util.Date` represents an instant in time. It's a direct analog of the + `java.time.Instant` type introduced in the JSR-310. Please consider using the + `java.time.Instant` (through [[instant]]) directly.", :tag java.util.Date} java-date java-time.pre-java8/java-date) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `java.sql.Date` out of any combination of arguments valid for + [[local-date]] or the `LocalDate` itself. + + Please consider using the JSR-310 Java Time types instead of `java.sql.Date` + if your drivers support them. + + Even though `java.sql.Date` extends a `java.util.Date`, it's supposed to be + used as a local date (no time component or time zone) for the purposes of + conversion from/to native JDBC driver DATE types.", :tag java.sql.Date} sql-date java-time.pre-java8/sql-date) +(def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2] [arg0 arg1 arg2 arg3] [arg0 arg1 arg2 arg3 arg4] [arg0 arg1 arg2 arg3 arg4 arg5] [arg0 arg1 arg2 arg3 arg4 arg5 arg6])), :doc "Creates a `java.sql.Timestamp` in the local time zone out of any combination + of arguments valid for [[local-date-time]] or the `LocalDateTime` + itself. + + Does not support `Timestamp` construction from an `Instant` or a long millis value---please use + [[instant->sql-timestamp]] for this purpose. + + Please consider using the JSR-310 Java Time types instead of + `java.sql.Timestamp` if your drivers support them. + + `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used + as a local date-time (no time zone) for the purposes of conversion from/to native + JDBC driver TIMESTAMP types.", :tag java.sql.Timestamp} sql-timestamp java-time.pre-java8/sql-timestamp) +(def ^{:arglists (quote ([instant-or-millis])), :doc "Creates a `java.sql.Timestamp` from the provided `instant-or-millis` - a + millisecond numeric time value or something convertible to an `Instant`. + + Please consider using the JSR-310 Java Time types instead of + `java.sql.Timestamp` if your drivers support them. + + `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used + as a local date-time (no time zone) for the purposes of conversion from/to native + JDBC driver TIMESTAMP types."} instant->sql-timestamp java-time.pre-java8/instant->sql-timestamp) +(java-time.util/when-class "java.sql.Time" (def ^{:arglists (quote ([] [arg0] [arg0 arg1] [arg0 arg1 arg2])), :doc "Creates a `java.sql.Time` out of any combination of arguments valid for + [[local-time]] (except the nanos constructor) or the `LocalTime` + itself. + + Please consider using the JSR-310 Java Time types instead of `java.sql.Time` + if your drivers support them. + + Even though `java.sql.Time` extends a `java.util.Date`, it's supposed to be + used as a local time (no date component or time zone) for the purposes of + conversion from/to native JDBC driver TIME types.", :tag java.sql.Time} sql-time java-time.pre-java8/sql-time)) +(defn ^{:doc "Moves the start instant of the interval to the given instant (or something + convertible to an instant): + + ``` + (move-start-to (interval 0 10000) (instant 5000)) + => # + ``` + + Fails if the new start instant falls after the end instant: + + ``` + (move-start-to (interval 0 10000) (millis 15000)) + => DateTimeException... + ```"} move-start-to ([i new-start] (java-time.interval/move-start-to i new-start))) +(defn ^{:doc "Moves the end of the interval to the given instant (or something + convertible to an instant): + + ``` + (move-end-to (interval 0 10000) (instant 15000)) + => # + ``` + + Fails if the new end instant falls before the start instant: + + ``` + (move-end-to (interval 0 10000) (millis -1)) + => DateTimeException... + ```"} move-end-to ([i new-end] (java-time.interval/move-end-to i new-end))) +(def ^{:arglists (quote ([i & os])), :doc "Moves the start instant of the interval by the sum of given + periods/durations/numbers of milliseconds: + + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` + + Fails if the new start instant falls after the end instant. + + ``` + (move-start-by (interval 0 10000) (millis 11000)) + ;=> DateTimeException... + ```"} move-start-by java-time.interval/move-start-by) +(def ^{:arglists (quote ([i & os])), :doc "Moves the end instant of the interval by the sum of given + periods/durations/numbers of milliseconds. + + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` + + Fails if the new end instant falls before the start instant. + + ``` + (move-end-by (interval 0 10000) (millis -11000)) + => DateTimeException... + ```"} move-end-by java-time.interval/move-end-by) +(defn ^{:doc "Gets the start instant of the interval"} start ([i] (java-time.interval/start i))) +(defn ^{:doc "Gets the end instant of the interval"} end ([i] (java-time.interval/end i))) +(defn ^{:doc "True if the interval contains the given instant or interval"} contains? ([i o] (java-time.interval/contains? i o))) +(defn ^{:doc "True if this interval overlaps the other one"} overlaps? ([i oi] (java-time.interval/overlaps? i oi))) +(defn ^{:doc "True if this interval abut with the other one"} abuts? ([i oi] (java-time.interval/abuts? i oi))) +(defn ^{:doc "Gets the overlap between this interval and the other one or `nil`"} overlap ([i oi] (java-time.interval/overlap i oi))) +(defn ^{:doc "Gets the gap between this interval and the other one or `nil`"} gap ([i oi] (java-time.interval/gap i oi))) +(java-time.util/when-class "org.threeten.extra.Temporals" (def ^{:arglists (quote ([^String o] [a b])), :doc "Constructs an interval out of a string, start and end instants or a start + + duration: + + ``` + (j/interval \"2010-01-01T00:00:00Z/2013-01-01T00:00:00Z\") + => # + + (j/interval (j/instant 100000) (j/instant 1000000)) + => # + + (j/interval (j/instant 100000) (j/duration 15 :minutes)) + => # + ``` + + Requires the optional `threeten-extra` dependency.", :tag org.threeten.extra.Interval} interval java-time.interval/interval) (def ^{:arglists (quote ([o])), :doc "True if `Interval`"} interval? java-time.interval/interval?) (def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `AmPm` for the given keyword name (`:am` or `:pm`), + ordinal or entity. Current AM/PM if no arguments given.", :tag org.threeten.extra.AmPm} am-pm java-time.single-field/am-pm) (def ^{:arglists (quote ([o])), :doc "True if `org.threeten.extra.AmPm`."} am-pm? java-time.single-field/am-pm?) (def ^{:arglists (quote ([] [v] [fmt arg])), :doc "Returns the `Quarter` for the given quarter keyword name (e.g. `:q1`), + ordinal or entity. Current quarter if no arguments given.", :tag org.threeten.extra.Quarter} quarter java-time.single-field/quarter) (def ^{:arglists (quote ([o])), :doc "True if `org.threeten.extra.Quarter`."} quarter? java-time.single-field/quarter?) (def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `DayOfMonth` for the given entity, clock, zone or day of month. + Current day of month if no arguments given.", :tag org.threeten.extra.DayOfMonth} day-of-month java-time.single-field/day-of-month) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.DayOfMonth`, otherwise false."} day-of-month? java-time.single-field/day-of-month?) (def ^{:arglists (quote ([] [arg] [fmt arg])), :doc "Returns the `DayOfYear` for the given entity, clock, zone or day of year. + Current day of year if no arguments given.", :tag org.threeten.extra.DayOfYear} day-of-year java-time.single-field/day-of-year) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.DayOfYear`, otherwise false."} day-of-year? java-time.single-field/day-of-year?) (def ^{:arglists (quote ([] [arg] [a b])), :doc "Returns the `YearQuarter` for the given entity, clock, zone or year with quarter. + Current year quarter if no arguments given.", :tag org.threeten.extra.YearQuarter} year-quarter java-time.single-field/year-quarter) (def ^{:arglists (quote ([o])), :doc "Returns true if `o` is `org.threeten.extra.YearQuarter`, otherwise false."} year-quarter? java-time.single-field/year-quarter?)) diff --git a/src/java_time/clock.clj b/src/java_time/clock.clj index 23cbcef..6770e87 100644 --- a/src/java_time/clock.clj +++ b/src/java_time/clock.clj @@ -1,13 +1,10 @@ (ns java-time.clock - (:require [java-time.core :as jt.c]) - (:import [java.time Clock Instant])) + (:import [java.time Clock])) (def ^:dynamic ^Clock *clock* nil) (defn make [f] - (if *clock* - (f *clock*) - (f (Clock/systemDefaultZone)))) + (f (or *clock* (Clock/systemDefaultZone)))) (defn with-clock-fn "Executes the given function in the scope of the provided clock. All the @@ -27,4 +24,4 @@ (zone-id)) => #" [c & forms] - `(with-clock-fn ~c (fn [] ~@forms))) + `(with-clock-fn ~c (fn [] (let [res# (do ~@forms)] res#)))) diff --git a/src/java_time/convert.clj b/src/java_time/convert.clj index f7e4216..242eea5 100644 --- a/src/java_time/convert.clj +++ b/src/java_time/convert.clj @@ -14,11 +14,13 @@ passed in `value-fn`. By default the actual value of the unit/field is produced. - (as-map (duration)) - => {:nanos 0, :seconds 0} + ``` + (as-map (duration)) + => {:nanos 0, :seconds 0} - (as-map (local-date 2015 1 1)) - => {:year 2015, :month-of-year 1, :day-of-month 1, ...}" + (as-map (local-date 2015 1 1)) + => {:year 2015, :month-of-year 1, :day-of-month 1, ...} + ```" ([e] (as-map e jt.c/value)) ([e value-fn] (jt.u/map-vals value-fn (jt.c/properties e)))) @@ -48,66 +50,71 @@ ;; BSD Licence (defn convert-amount "Converts an amount from one unit to another. Returns a map of: - * `:whole` - the whole part of the conversion in the `to` unit - * `:remainder` - the remainder in the `from` unit + + * `:whole` - the whole part of the conversion in the `to` unit + * `:remainder` - the remainder in the `from` unit Arguments may be keywords or instances of `TemporalUnit`. - Converts between precise units - nanos up to weeks, treating days as exact - multiples of 24 hours. Also converts between imprecise units - months up to - millenia. See `ChronoUnit` and `IsoFields` for all of the supported units. + Converts between precise units--nanos up to weeks---treating days as exact + multiples of 24 hours. Also converts between imprecise units---months up to + millennia. See `ChronoUnit` and `IsoFields` for all of the supported units. Does not convert between precise and imprecise units. Throws `ArithmeticException` if long overflow occurs during computation. - (convert-amount 10000 :seconds :hours) - => {:remainder 2800 :whole 2}" + ``` + (convert-amount 10000 :seconds :hours) + => {:remainder 2800 :whole 2} + ```" [amount from-unit to-unit] (let [^TemporalUnit from-unit (jt.p/unit from-unit) ^TemporalUnit to-unit (jt.p/unit to-unit)] (if (= from-unit to-unit) {:whole amount, :remainder 0} - (cond (and (precise? from-unit) (precise? to-unit)) - (convert-unit (long amount) - (-> from-unit .getDuration .toNanos) - (-> to-unit .getDuration .toNanos)) - - (and (not (precise? from-unit)) (not (precise? to-unit))) - (convert-unit (long amount) - (month-month-factor (jt.p/unit-key from-unit)) - (month-month-factor (jt.p/unit-key to-unit))) - - :else (-> (format "Cannot convert between precise (nanos up to weeks) and imprecise units, got: %s to %s!" - from-unit to-unit) - (IllegalArgumentException.) - (throw)))))) - -(defn ^Date to-java-date + (let [from-precise? (precise? from-unit) + to-precise? (precise? to-unit)] + (cond (and from-precise? to-precise?) + (convert-unit (long amount) + (-> from-unit .getDuration .toNanos) + (-> to-unit .getDuration .toNanos)) + + (and (not from-precise?) (not to-precise?)) + (convert-unit (long amount) + (month-month-factor (jt.p/unit-key from-unit)) + (month-month-factor (jt.p/unit-key to-unit))) + + :else (-> (format "Cannot convert between precise (nanos up to weeks) and imprecise units, got: %s to %s!" + from-unit to-unit) + IllegalArgumentException. + throw)))))) + +(defn ^:deprecated ^java.util.Date to-java-date "Converts a date entity to a `java.util.Date`. *Deprecated*: This function only has a single arity and works for entities directly - convertible to `java.time.Instant`. Please consider using `java-date` + convertible to `java.time.Instant`. Please consider using [[java-date]] instead." [o] - (if (instance? Date o) o - (Date/from (jt.t/instant o)))) + (cond-> o + (not (instance? Date o)) (-> jt.t/instant Date/from))) -(defn ^java.sql.Date to-sql-date +(defn ^:deprecated ^java.sql.Date to-sql-date "Converts a local date entity to a `java.sql.Date`. *Deprecated*: This function only has a single arity and works for entities directly - convertible to `java.time.LocalDate`. Please consider using `sql-date` + convertible to `java.time.LocalDate`. Please consider using [[sql-date]] instead." [o] (java.sql.Date/valueOf (jt.l/local-date o))) -(defn ^java.sql.Timestamp to-sql-timestamp +(defn ^:deprecated ^java.sql.Timestamp to-sql-timestamp "Converts a date entity to a `java.sql.Timestamp`. *Deprecated*: This function only has a single arity and works for entities directly - convertible to `java.time.Instant`. Please consider using `sql-timestamp` + convertible to `java.time.Instant`. Please consider using [[sql-timestamp]] instead." [o] (java.sql.Timestamp/valueOf (jt.l/local-date-time o))) diff --git a/src/java_time/core.clj b/src/java_time/core.clj index e8f0204..da33623 100644 --- a/src/java_time/core.clj +++ b/src/java_time/core.clj @@ -1,5 +1,6 @@ (ns java-time.core - (:refer-clojure :exclude (zero? range max min abs)) + (:refer-clojure :exclude (zero? range max min abs < > <= >= * - + neg? =)) + (:require [clojure.core :as cc]) (:import [java.time.temporal ValueRange] [java.time.chrono Chronology])) @@ -22,7 +23,7 @@ "True if the `o` entity supports the `p` property")) (defprotocol HasChronology - (^Chronology chronology [o] + (^java.time.chrono.Chronology chronology [o] "The `Chronology` of the entity")) (defprotocol HasFields @@ -48,22 +49,6 @@ "Value of property/unit identified by key/object `k` of the temporal entity `o`")) -(defn as - "Values of property/unit identified by keys/objects `ks` of the temporal - entity `o`, e.g. - - (as (duration 1 :hour) :minutes) - => 60 - - (as (local-date 2015 9) :year :month-of-year) - => [2015 9]" - ([o k] - (as* o k)) - ([o k1 k2] - [(as* o k1) (as* o k2)]) - ([o k1 k2 & ks] - (concat (as o k1 k2) (mapv #(as* o %) ks)))) - (defprotocol ReadableProperty (value [p] "Value of the property")) @@ -102,11 +87,13 @@ (time-between [o e u] "Time between temporal entities `o` and `e` in unit `u`. - (j/time-between (j/local-date 2015) (j/local-date 2016) :days) - => 365 + ``` + (j/time-between (j/local-date 2015) (j/local-date 2016) :days) + => 365 - (j/time-between :days (j/local-date 2015) (j/local-date 2016)) - => 365")) + (j/time-between :days (j/local-date 2015) (j/local-date 2016)) + => 365 + ```")) (defprotocol KnowsIfLeap (leap? [o] @@ -131,7 +118,7 @@ (defprotocol Multipliable (multiply-by [o v] - "Entity `o` mutlitplied by the value `v`")) + "Entity `o` multiplied by the value `v`")) (defprotocol Ordered (single-before? [a b] @@ -139,79 +126,147 @@ (single-after? [a b] "Internal use")) -(defn max - "Latest/longest of the given time entities. Entities should be of the same - type" - [o & os] - (last (sort (cons o os)))) +(defprotocol Convert + (-convert [a b] "Internal use. + Convert `b` to a value compatible with `a`'s implementation + of single-after? etc, and one that is useable as the first argument + to single-after? etc.")) -(defn min - "Earliest/shortest of the given time entities. Entities should be of the same - type" - [o & os] - (first (sort (cons o os)))) +(extend-type Object + Convert + (-convert [a b] b)) + +(defn as + "Values of property/unit identified by keys/objects `ks` of the temporal + entity `o`, e.g. + + ``` + (as (duration 1 :hours) :minutes) + => 60 + + (as (local-date 2015 9) :year :month-of-year) + => [2015 9] + ```" + ([o k] + (as* o k)) + ([o k1 k2] + [(as* o k1) (as* o k2)]) + ([o k1 k2 & ks] + (into (as o k1 k2) (map #(as* o %)) ks))) (defn before? - "Returns a truthy value if time entities are ordered from the earliest to the - latest (same semantics as `<`): + "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. - (before? (local-date 2009) (local-date 2010) (local-date 2011)) - => truthy... + ``` + (before? (local-date 2009) (local-date 2010) (local-date 2011)) + => true - (before? (interval (instant 10000) (instant 1000000)) - (instant 99999999)) - => truthy..." + (before? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```" ([x] true) - ([x y] (single-before? x y)) + ([x y] (single-before? x (-convert x y))) ([x y & more] - (if (before? x y) - (if (next more) - (recur y (first more) (next more)) - (before? y (first more))) - false))) + (let [y (-convert x y)] + (if (single-before? x y) + (if-some [n (next more)] + (recur y (first more) n) + (single-before? y (-convert y (first more)))) + false)))) (defn after? - "Returns a truthy value if time entities are ordered from the latest to the - earliest (same semantics as `>`): + "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. - (after? (local-date 2011) (local-date 2010) (local-date 2009)) - => truthy... + ``` + (after? (local-date 2011) (local-date 2010) (local-date 2009)) + => true - (after? (instant 99999999) - (interval (instant 10000) (instant 1000000))) - => truthy..." + (after? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```" ([x] true) - ([x y] (single-after? x y)) + ([x y] (single-after? x (-convert x y))) ([x y & more] - (if (after? x y) - (if (next more) - (recur y (first more) (next more)) - (after? y (first more))) - false))) - -(def not-after? - "Similar to [[before?]], but also returns truthy if the inputs are equal." - (complement after?)) - -(def not-before? - "Similar to [[after?]], but also returns truthy if the inputs are equal." - (complement before?)) + (let [y (-convert x y)] + (if (single-after? x y) + (if-some [n (next more)] + (recur y (first more) n) + (single-after? y (-convert y (first more)))) + false)))) + +(defn ^:private single-not-after? [x y] + (or (cc/= x y) + (single-before? x y))) + +(defn not-after? + "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (not-after? (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (not-after? (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```" + ([x] true) + ([x y] (single-not-after? x (-convert x y))) + ([x y & more] + (let [y (-convert x y)] + (and (single-not-after? x y) + (if-some [n (next more)] + (recur y (first more) n) + (single-not-after? y (-convert y (first more)))))))) + +(defn ^:private single-not-before? [x y] + (or (cc/= x y) + (single-after? x y))) + +(defn not-before? + "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (not-before? (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (not-before? (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```" + ([x] true) + ([x y] (single-not-before? x (-convert x y))) + ([x y & more] + (let [y (-convert x y)] + (and (single-not-before? x y) + (if-some [n (next more)] + (recur y (first more) n) + (single-not-before? y (-convert y (first more)))))))) (defn plus "Adds all of the `os` to the time entity `o`. `plus` is not commutative, the first argument is always the entity which will accumulate the rest of the arguments. - (j/plus (j/local-date 2015) (j/years 1)) - => " + ``` + (j/plus (j/local-date 2015) (j/years 1)) + => + ```" [o & os] (seq-plus o os)) (defn minus "Subtracts all of the `os` from the time entity `o` - (j/minus (j/local-date 2015) (j/years 1)) - => " + ``` + (j/minus (j/local-date 2015) (j/years 1)) + => + ```" [o & os] (if (seq os) (seq-minus o os) @@ -228,20 +283,20 @@ Plusable (seq-plus [n xs] - (apply + n xs)) + (apply cc/+ n xs)) Minusable (seq-minus [n xs] - (apply - n xs)) + (apply cc/- n xs)) Multipliable (multiply-by [n v] - (* n (value v))) + (cc/* n (value v))) Amount - (zero? [n] (clojure.core/zero? n)) - (negative? [n] (neg? n)) - (negate [n] (- n)) + (zero? [n] (cc/zero? n)) + (negative? [n] (cc/neg? n)) + (negate [n] (cc/- n)) (abs [n] (Math/abs (long n)))) (extend-type nil @@ -256,3 +311,127 @@ :largest-min-value (fn [p] (.getLargestMinimum ^ValueRange (range p))) :smallest-max-value (fn [p] (.getSmallestMaximum ^ValueRange (range p))) :max-value (fn [p] (.getMaximum ^ValueRange (range p)))}) + +;; vars named after excluded clojure.core vars + +(def ^{:arglists '([x] [x y] [x y & more])} + <= + "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<=`), otherwise `false`. + + ``` + (j/<= (local-date 2009) (local-date 2010) (local-date 2011)) + ;=> true + + (j/<= (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + ;=> true + ```" + not-after?) + +(def ^{:arglists '([x] [x y] [x y & more])} + >= + "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>=`), otherwise `false`. + + ``` + (j/>= (local-date 2011) (local-date 2010) (local-date 2009)) + ;=> true + + (j/>= (instant 99999999) + (interval (instant 10000) (instant 1000000))) + ;=> true + ```" + not-before?) + +(def ^{:arglists '([x] [x y] [x y & more])} + < + "Returns `true` if time entities are ordered from the earliest to the + latest (same semantics as `<`), otherwise `false`. + + ``` + (j/< (local-date 2009) (local-date 2010) (local-date 2011)) + => true + + (j/< (interval (instant 10000) (instant 1000000)) + (instant 99999999)) + => true + ```" + before?) + +(def ^{:arglists '([x] [x y] [x y & more])} + > + "Returns `true` if time entities are ordered from the latest to the + earliest (same semantics as `>`), otherwise `false`. + + ``` + (j/> (local-date 2011) (local-date 2010) (local-date 2009)) + => true + + (j/> (instant 99999999) + (interval (instant 10000) (instant 1000000))) + => true + ```" + after?) + +(def ^{:arglists '([o & os])} + + + "Adds all of the `os` to the time entity `o`. `+` is not commutative, the + first argument is always the entity which will accumulate the rest of the + arguments. + + ``` + (j/+ (j/local-date 2015) (j/years 1)) + => + ```" + plus) + +(def ^{:arglists '([o & os])} + - + "Subtracts all of the `os` from the time entity `o` + + ``` + (j/- (j/local-date 2015) (j/years 1)) + => + ```" + minus) + +(defn max + "Latest/longest of the given time entities. Entities should be of the same + type" + [o & os] + (first (sort #(compare %2 %1) (cons o os)))) + +(defn min + "Earliest/shortest of the given time entities. Entities should be of the same + type" + [o & os] + (first (sort (cons o os)))) + +(defn = + "Returns true if all time entities represent the same time, otherwise false. + + `j/=` is not commutative, the first argument is always the entity which will + accumulate the rest of the arguments. + + e.g., (j/= (j/day-of-week :thursday) :thursday) => true" + ([x] true) + ([x y] (cc/= x (-convert x y))) + ([x y & more] + (let [y (-convert x y)] + (and (cc/= x y) + (if-some [n (next more)] + (recur y (first more) n) + (cc/= y (-convert y (first more)))))))) + +;; these can't be aliased since they're protocol methods + +(defn neg? + "True if the amount is negative" + [a] + (negative? a)) + +(defn * + "Entity `o` multiplied by the value `v`" + [o v] + (multiply-by o v)) diff --git a/src/java_time/defconversion.clj b/src/java_time/defconversion.clj index 44920c6..139e31b 100644 --- a/src/java_time/defconversion.clj +++ b/src/java_time/defconversion.clj @@ -10,9 +10,8 @@ vs) (defn- to-seq [in] - (if (sequential? in) - in - (vector in))) + (cond-> in + (not (sequential? in)) vector)) (defn- wrap-validation [from to f] (fn [vs] @@ -22,15 +21,15 @@ (defn- combinations [xs f cost] (let [idxs (g/continuous-combinations (count xs))] (for [combo idxs] - (vector (fn [& vs] - (let [res (to-seq (apply f vs))] - (subvec res (first combo) (inc (last combo))))) - (g/types (subvec xs (first combo) (inc (last combo)))) - (if (= (count idxs) (count xs)) - cost - ;; TODO: mark as lossy conversion - ;; currently we just incur a 0.5*number of types dropped penalty - (+ cost (* 0.5 (- (count xs) (count combo))))))))) + [(fn [& vs] + (let [res (to-seq (apply f vs))] + (subvec res (first combo) (inc (last combo))))) + (g/types (subvec xs (first combo) (inc (last combo)))) + (cond-> cost + ;; TODO: mark as lossy conversion + ;; currently we just incur a 0.5*number of types dropped penalty + (not= (count idxs) (count xs)) + (+ (* 0.5 (- (count xs) (count combo)))))]))) (def ^:dynamic *fail-on-duplicate-conversion?* true) @@ -53,32 +52,27 @@ (defn types-of [xs] (g/types (map type xs))) -(defn- call-conversion [nm tp args] - `(if-let [[path# fn#] (g/conversion-fn - @graph - (types-of ~args) - (g/types ~(to-seq tp)))] - (if-let [result# - (try (fn# ~args) - (catch Exception e# - (throw - (ex-info "Conversion failed" - {:path (:path path#), :arguments ~args, :to ~tp} e#))))] - (if (instance? clojure.lang.ISeq ~tp) - result# - (first result#)) - (throw (ex-info - (format "Conversion from %s to %s returned nil!" - ~args ~tp ~(str nm)) - {:arguments ~args, :to ~tp, :constructor ~nm}))) - (throw (ex-info (format "Could not convert %s to %s!" ~args ~tp ~(str nm)) - {:arguments ~args, :to ~tp, :constructor ~nm})))) +(defn ^:internal call-conversion [nm tp args] + (if-let [[path f] (g/conversion-fn + @graph + (types-of args) + (g/types [tp]))] + (or (try (first (f args)) + (catch Exception e + (throw + (ex-info "Conversion failed" + {:path (:path path), :arguments args, :to tp} + e)))) + (throw (ex-info + (format "Conversion from %s to %s returned nil!" args tp) + {:arguments args, :to tp, :constructor nm}))) + (throw (ex-info (format "Could not convert %s to %s!" args tp) + {:arguments args, :to tp, :constructor nm})))) (defn- gen-implicit-arities [nm tp arities] (for [arity arities] - (let [args (mapv #(gensym (str "arg_" (inc %) "_")) (range arity))] - `([~@args] - ~(call-conversion nm tp args))))) + (let [args (mapv #(gensym (str "arg" (inc %))) (range arity))] + `(~args (call-conversion ~nm ~tp ~args))))) (defn get-path [from to] (let [[p _] (g/conversion-fn @graph @@ -86,8 +80,14 @@ (g/types (to-seq to)))] (select-keys p [:path :cost]))) -(defmacro deffactory [nm docstring _ tp _ implicit-arities & fn-bodies] - (let [fn-name (with-meta nm {:tag tp}) +(defmacro deffactory [nm docstring returnskw tp implicit-arities-kw implicit-arities & fn-bodies] + (assert (string? docstring)) + (assert (= :returns returnskw)) + (assert (= :implicit-arities implicit-arities-kw)) + (let [^Class tpcls (resolve tp) + _ (assert (class? tpcls) (str tp " is not resolvable")) + tp (-> ^Class tpcls .getName symbol) + fn-name (with-meta nm {:tag tp}) explain-fn-name (symbol (str "path-to-" nm)) predicate-name (symbol (str nm "?"))] `(do (defn ~fn-name ~docstring @@ -96,6 +96,7 @@ (gen-implicit-arities nm tp implicit-arities))) (defn ~predicate-name - ~(str "True if an instance of " tp ".") + ~(str "Returns true if `v` is an instance of " tp ", otherwise false.") + {:arglists '[[~'v]]} [v#] (instance? ~tp v#))))) diff --git a/src/java_time/format.clj b/src/java_time/format.clj index af515f8..724d464 100644 --- a/src/java_time/format.clj +++ b/src/java_time/format.clj @@ -1,8 +1,6 @@ (ns java-time.format (:refer-clojure :exclude (format)) - (:require [clojure.string :as string] - [java-time.core :as jt.c] - [java-time.util :as jt.u]) + (:require [java-time.util :as jt.u]) (:import [java.time.temporal TemporalAccessor] [java.time.format DateTimeFormatter DateTimeFormatterBuilder ResolverStyle] java.util.Locale)) @@ -29,8 +27,9 @@ [(.. (.replace n \_ \-) toString (toLowerCase (Locale/US))) fmt])))) (defn- get-resolver-style [s] - (if (instance? ResolverStyle s) s - (case s + (cond-> s + (not (instance? ResolverStyle s)) + (case :strict ResolverStyle/STRICT :smart ResolverStyle/SMART :lenient ResolverStyle/LENIENT))) @@ -42,7 +41,7 @@ (.parseCaseInsensitive fmt-builder)) fmt-builder)) -(defn ^DateTimeFormatter formatter +(defn ^java.time.format.DateTimeFormatter formatter "Constructs a DateTimeFormatter out of a * format string - \"yyyy/MM/dd\", \"HH:mm\", etc. @@ -50,7 +49,7 @@ Accepts a map of options as an optional second argument: - * `resolver-style` - either `:strict`, `:smart `or `:lenient` + * `resolver-style` - either `:strict`, `:smart` or `:lenient` * `case` - either `:insensitive` or `:sensitive` (defaults to :sensitive)" ([fmt] (formatter fmt {})) @@ -60,11 +59,9 @@ (string? fmt) (.. (get-case-formatter case) (appendPattern fmt) toFormatter) - :else (get predefined-formatters (name fmt))) - fmt (if resolver-style - (.withResolverStyle fmt (get-resolver-style resolver-style)) - fmt)] - fmt))) + :else (get predefined-formatters (name fmt)))] + (cond-> fmt + resolver-style (.withResolverStyle (get-resolver-style resolver-style)))))) (defn format "Formats the given time entity as a string. @@ -73,11 +70,13 @@ formatter key, e.g. `:iso-offset-time`, as a first argument. Given one argument uses the default format. - (format (zoned-date-time)) - \"2015-03-21T09:22:46.677800+01:00[Europe/London]\" + ``` + (format (zoned-date-time)) + => \"2015-03-21T09:22:46.677800+01:00[Europe/London]\" - (format :iso-date (zoned-date-time)) - \"2015-03-21+01:00\"" + (format :iso-date (zoned-date-time)) + \"2015-03-21+01:00\" + ```" ([o] (str o)) ([fmt o] (.format (formatter fmt) o))) diff --git a/src/java_time/graph.clj b/src/java_time/graph.cljc similarity index 61% rename from src/java_time/graph.clj rename to src/java_time/graph.cljc index 88cf72e..67dfe9c 100644 --- a/src/java_time/graph.clj +++ b/src/java_time/graph.cljc @@ -1,15 +1,16 @@ (ns java-time.graph (:require [clojure.set :as sets] [clojure.string :as string] - [java-time.potemkin.util :as u] - [java-time.util :as jt.u]) - (:import [java.util PriorityQueue Queue])) + [java-time.potemkin.util :as u]) + #?@(:bb [] + :default [(:import [java.util PriorityQueue])])) ;; Concept heavily inspired by Zach Tellman's ByteStreams ;; https://github.com/ztellman/byte-streams/blob/master/src/byte_streams/graph.clj (deftype Conversion [f ^double cost] Object + #?@(:bb [] :default [ (equals [_ x] (and (instance? Conversion x) @@ -17,11 +18,13 @@ (== cost (.cost ^Conversion x)))) (hashCode [_] (bit-xor (System/identityHashCode f) (unchecked-int cost))) + ]) (toString [_] (str "Cost:" cost))) (deftype Types [types ^int arity] Object + #?@(:bb [] :default [ (equals [_ o] (and (instance? Types o) (and (= arity (.arity ^Types o)) @@ -33,6 +36,7 @@ false))))) (hashCode [o] (bit-xor (hash types) arity)) + ]) (toString [_] (pr-str types))) @@ -48,11 +52,12 @@ (def max-extent 2) (defn types [ts] - (let [cnt (count ts)] + (let [ts (vec ts) + cnt (count ts)] (when (> cnt max-arity) (throw (ex-info (format "Maximum arity supported by conversion graph is %s!" max-arity) {:types ts}))) - (Types. (vec ts) cnt))) + (Types. ts cnt))) (defn- assignable-type? [a b] (or (= a b) (.isAssignableFrom ^Class b a))) @@ -63,12 +68,13 @@ (fn [^Types a ^Types b] (or (= a b) (and (= (.arity a) (.arity b)) - (let [ta (.types a), tb (.types b)] - (loop [idx 0] - (when (assignable-type? (nth ta idx) (nth tb idx)) - (if (> (.arity a) (inc idx)) - (recur (inc idx)) - true))))))))) + (boolean + (let [ta (.types a), tb (.types b)] + (loop [idx 0] + (when (assignable-type? (nth ta idx) (nth tb idx)) + (if (> (.arity a) (inc idx)) + (recur (inc idx)) + true)))))))))) (defprotocol IConversionGraph (get-conversion [_ src dst]) @@ -78,15 +84,15 @@ (possible-conversions [_ src])) (defn- expand [[a b]] - (when-not (empty? b) + (when-some [[bf & br] (seq b)] (cons - [(conj a (first b)) (rest b)] - (expand [a (rest b)])))) + [(conj a bf) br] + (expand [a br])))) (defn- combinations [n s] (letfn [(combos [n s] (if (zero? n) - (list (vector (vector) s)) + (list [[] s]) (mapcat expand (combos (dec n) s))))] (map first (combos n s)))) @@ -94,39 +100,39 @@ (u/fast-memoize (fn [n] (let [rng (range n)] - (->> (map inc rng) - (map #(combinations % rng)) - (apply concat) - (filterv #(apply = 1 (map - (rest %) %)))))))) + (into [] (comp (map inc) + (map #(combinations % rng)) + cat + (filter #(apply = 1 (map - (rest %) %)))) + rng))))) (defn- as-source [types-so-far t [dst c]] - (vector - (vector (types (conj types-so-far t)) dst) - c)) + [[(types (conj types-so-far t)) dst] + c]) (defn- search-for-possible-sources [vresult m types-so-far k more-arity-steps] - (u/doit [[t r] m] - (when (assignable-type? k t) - (if-not more-arity-steps - (vswap! vresult concat (mapv #(as-source types-so-far t %) r)) - (search-for-possible-sources vresult r - (conj types-so-far t) - (first more-arity-steps) - (next more-arity-steps)))))) + (run! (fn [[t r]] + (when (assignable-type? k t) + (if-not more-arity-steps + (vswap! vresult into (map #(as-source types-so-far t %)) r) + (search-for-possible-sources vresult r + (conj types-so-far t) + (first more-arity-steps) + (next more-arity-steps))))) + m)) (defn- collect-targets [v] (reduce (fn [r [k v]] - (if (map? v) - (concat r (collect-targets v)) - (concat r v))) - (vector) v)) + (into r (cond-> v + (map? v) collect-targets))) + [] v)) (defn- add-conversion [m ^Types src dst conversion] (let [add #(update % (peek (.types src)) - (fnil conj (vector)) - (vector dst conversion))] + (fnil conj []) + [dst conversion])] (if (> (.arity src) 1) (update-in m (pop (.types src)) add) (add m)))) @@ -134,7 +140,7 @@ (deftype ConversionGraph [m-by-arity srcs] IConversionGraph (get-conversion [_ src dst] - (let [m (get m-by-arity (.arity ^Types src))] + (let [m (m-by-arity (.arity ^Types src))] (->> (get-in m (.types ^Types src)) (some #(= dst (first %)))))) (assoc-conversion [_ src dst f cost] @@ -144,19 +150,19 @@ (conj srcs src))) (possible-sources [_] srcs) (equivalent-targets [_ dst] - (->> (vals m-by-arity) - (mapcat collect-targets) - (map first) - (filter #(assignable? % dst)) - (set))) + (into #{} (comp (mapcat collect-targets) + (map first) + (filter #(assignable? % dst))) + (vals m-by-arity))) (possible-conversions [_ src] - (let [result (volatile! (vector))] + (let [^Types src src + result (volatile! [])] (search-for-possible-sources result - (get m-by-arity (.arity ^Types src)) - (vector) - (first (.types ^Types src)) - (next (.types ^Types src))) + (m-by-arity (.arity src)) + [] + (first (.types src)) + (next (.types src))) @result))) (defn conversion-graph [] @@ -164,55 +170,68 @@ (zipmap (map inc (range max-arity)) (repeat {})) #{})) (defrecord ConversionPath [path fns visited? cost] + #?@(:bb [] :default [ Comparable (compareTo [_ x] (let [cmp (compare cost (.cost ^ConversionPath x))] (if (zero? cmp) (compare (count path) (count (.path ^ConversionPath x))) cmp))) + ]) Object (toString [_] (str path cost))) (defn- conj-path [^ConversionPath p src dst ^Conversion c] (ConversionPath. - (conj (.path p) (vector src dst)) + (conj (.path p) [src dst]) (conj (.fns p) (.f c)) (conj (.visited? p) dst) (+ (.cost p) (.cost c)))) -(def graph-conversion-path - (fn [g src dst] - (let [path (ConversionPath. (vector) (vector) #{src} 0)] - (if (assignable? src dst) - path - (let [q (doto (PriorityQueue.) (.add path)) - dsts (equivalent-targets g dst)] - (loop [] - (when-let [^ConversionPath p (.poll q)] - (let [curr (or (-> p .path last second) src)] - (if (some #(assignable? curr %) dsts) - p - (do - (u/doit [[[src dst] c] (possible-conversions g curr)] - (when (and (> max-path-length (count (.path p))) - (not ((.visited? p) dst))) - (.add q (conj-path p src dst c)))) - (recur))))))))))) +(defn graph-conversion-path [g src dst] + (let [path (ConversionPath. [] [] #{src} 0)] + (if (assignable? src dst) + path + (let [q #?(:bb (atom ()) + :default (PriorityQueue.)) + add #?(:bb #(swap! q (fn [prev] + (sort-by (fn [^ConversionPath p] + [(.cost p) (count (.path p))]) + (fn [a b] (compare b a)) + (conj prev %)))) + :default #(.add q %)) + poll #?(:bb #(-> (swap-vals! q next) ffirst) + :default #(.poll q)) + _ (add path) + dsts (equivalent-targets g dst)] + (loop [] + (when-some [^ConversionPath p (poll)] + (let [curr (or (-> p .path peek second) src)] + (if (some #(assignable? curr %) dsts) + p + (do (run! (fn [[[src dst] c]] + (when (and (> max-path-length (count (.path p))) + (not ((.visited? p) dst))) + (add (conj-path p src dst c)))) + (possible-conversions g curr)) + (recur)))))))))) (defn- replace-range [v replacement idxs] - (concat (subvec v 0 (first idxs)) - replacement - (subvec v (inc (last idxs)) (count v)))) + (-> v + (subvec 0 (first idxs)) + (into replacement) + (into (subvec v (inc (peek idxs)) (count v))))) (defn- index-conversions [^Types src idxs [[_ ^Types replacement] ^Conversion conv]] - (vector src (types (replace-range (.types src) (.types replacement) idxs)) - (fn [vs] - (let [vs (vec vs)] - (replace-range vs - ((.f conv) (subvec vs (first idxs) (inc (last idxs)))) - idxs))) - (.cost conv))) + [src + (types (replace-range (.types src) (.types replacement) idxs)) + (fn [vs] + (let [vs (vec vs)] + (replace-range vs + ((.f conv) (subvec vs (first idxs) (inc (peek idxs)))) + idxs))) + (.cost conv)]) (defn- sub-conversions "Given an `src` types, generate all of the conversions from these types that @@ -229,11 +248,11 @@ [src -> String]" [g ^Types src] (if (> (.arity src) max-arity) - (vector) + [] (->> (continuous-combinations (.arity src)) (mapcat (fn [idxs] - (let [^Types input (types (subvec (.types src) (first idxs) (inc (last idxs))))] + (let [^Types input (types (subvec (.types src) (first idxs) (inc (peek idxs))))] (->> (possible-conversions g input) (filter (fn [[[_ ^Types replacement] _]] (>= max-arity (+ (.arity replacement) @@ -241,7 +260,8 @@ (map #(index-conversions src idxs %))))))))) (defn- with-conversions [g convs] - (loop [g g, new-conversions (vector) + (loop [g g + new-conversions [] [src dst f cost :as con] (first convs) convs (next convs)] (if con @@ -257,16 +277,15 @@ ;; we want to skip the branches that contain the destination types as their part. ;; In our conversion world it's very unlikely that a value will be reduced to ;; the value of the same type. -(def contains-types? +(defn contains-types? "True if `a` contains `b` as its part." - (fn [^Types a, ^Types b] - (and (not= (.arity a) (.arity b)) - (let [ta (.types a), tb (.types b)] - (loop [idx 0] - (when (>= (.arity a) (+ idx (.arity b))) - (if (= tb (subvec ta idx (+ idx (.arity b)))) - true - (recur (inc idx))))))))) + [^Types a, ^Types b] + (and (not= (.arity a) (.arity b)) + (let [ta (.types a), tb (.types b)] + (loop [idx 0] + (when (>= (.arity a) (+ idx (.arity b))) + (or (= tb (subvec ta idx (+ idx (.arity b)))) + (recur (inc idx)))))))) ;; if a graph's sources do not contain all of the types present in the ;; requested source and the destination doesn't contain them either we conclude @@ -288,7 +307,7 @@ [new-conversions g'] (with-conversions g more-conversions) accepted-conversions (filter (fn [[conv-src _ _ cost]] (>= max-cost cost)) new-conversions)] - (recur g' (reduce (fn [q [_ dst _ _]] (conj q (vector dst (inc step)))) + (recur g' (reduce (fn [q [_ dst _ _]] (conj q [dst (inc step)])) (pop q) accepted-conversions)))) g))) @@ -299,16 +318,15 @@ (let [g' (expand-frontier g src max-extent)] (graph-conversion-path g' src dst)))))) -(defn- convert-via [path] - (condp = (count (:path path)) - 0 (vector path (fn [x] x)) - 1 (vector path (->> path :fns first)) - (let [fns (->> path :fns (apply vector))] - (vector path (fn [v] (reduce (fn [v f] (f v)) v fns)))))) +(defn- convert-via [{:keys [fns] :as path}] + (case (count (:path path)) + 0 [path identity] + 1 [path (first fns)] + [path (fn [v] (reduce (fn [v f] (f v)) v fns))])) (defn conversion-fn "Create a function which will convert between the `src` and the `dst` `Types`." [g src dst] - (when-let [path (conversion-path g src dst)] + (when-some [path (conversion-path g src dst)] (convert-via path))) diff --git a/src/java_time/interval.clj b/src/java_time/interval.clj index 17bfff1..74df68f 100644 --- a/src/java_time/interval.clj +++ b/src/java_time/interval.clj @@ -1,7 +1,6 @@ (ns java-time.interval (:refer-clojure :exclude [contains?]) - (:require [clojure.string :as string] - [java-time.util :as jt.u] + (:require [java-time.util :as jt.u] [java-time.core :as jt.c] [java-time.temporal :as jt.t] [java-time.amount :as jt.a]) @@ -16,24 +15,32 @@ "Moves the start instant of the interval to the given instant (or something convertible to an instant): + ``` (move-start-to (interval 0 10000) (instant 5000)) => # + ``` - Fails if the new start instant falls after the end instant: + Fails if the new start instant falls after the end instant: + ``` (move-start-to (interval 0 10000) (millis 15000)) - => DateTimeException...") + => DateTimeException... + ```") (move-end-to [i new-end] "Moves the end of the interval to the given instant (or something convertible to an instant): + ``` (move-end-to (interval 0 10000) (instant 15000)) => # + ``` - Fails if the new end instant falls before the start instant: + Fails if the new end instant falls before the start instant: + ``` (move-end-to (interval 0 10000) (millis -1)) - => DateTimeException...") + => DateTimeException... + ```") (start [i] "Gets the start instant of the interval") (end [i] "Gets the end instant of the interval") (contains? [i o] "True if the interval contains the given instant or interval") @@ -54,6 +61,7 @@ "Constructs an interval out of a string, start and end instants or a start + duration: + ``` (j/interval \"2010-01-01T00:00:00Z/2013-01-01T00:00:00Z\") => # @@ -62,6 +70,7 @@ (j/interval (j/instant 100000) (j/duration 15 :minutes)) => # + ``` Requires the optional `threeten-extra` dependency." ([^String o] (Interval/parse o)) @@ -113,11 +122,11 @@ jt.c/Ordered (single-before? [i o] (if (jt.t/instant? o) - (.isBefore (.getEnd i) o) - (.isBefore (.getEnd i) (.getStart ^Interval o)))) + (.isBefore i ^Instant o) + (.isBefore i ^Interval o))) (single-after? [i o] (if (jt.t/instant? o) - (.isAfter (.getStart i) o) - (.isAfter (.getStart i) (.getEnd ^Interval o)))) + (.isAfter i ^Instant o) + (.isAfter i ^Interval o))) jt.c/As (as* [o k] @@ -127,24 +136,32 @@ "Moves the start instant of the interval by the sum of given periods/durations/numbers of milliseconds: - (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) - => # + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` Fails if the new start instant falls after the end instant. - (move-start-by (interval 0 10000) (millis 11000)) - ; => DateTimeException..." + ``` + (move-start-by (interval 0 10000) (millis 11000)) + ;=> DateTimeException... + ```" [i & os] (seq-move-start-by i os)) (defn move-end-by "Moves the end instant of the interval by the sum of given periods/durations/numbers of milliseconds. - (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) - => # + ``` + (move-start-by (interval 0 10000) (millis 1000) (seconds 1)) + => # + ``` Fails if the new end instant falls before the start instant. - (move-end-by (interval 0 10000) (millis -11000)) - => DateTimeException..." + ``` + (move-end-by (interval 0 10000) (millis -11000)) + => DateTimeException... + ```" [i & os] (seq-move-end-by i os)) diff --git a/src/java_time/local.clj b/src/java_time/local.clj index de5928b..7390366 100644 --- a/src/java_time/local.clj +++ b/src/java_time/local.clj @@ -14,17 +14,17 @@ * no arguments - current local-date * one argument - + clock - + another temporal entity - + string representation - + year + + clock + + another temporal entity + + string representation + + year * two arguments - + formatter (format) and a string - + an instant and a zone id - + another temporal entity and an offset (preserves local time) - + year and month + + formatter (format) and a string + + an instant and a zone id + + another temporal entity and an offset (preserves local time) + + year and month * three arguments - + year, month and date" + + year, month and date" :returns LocalDate :implicit-arities [1 2 3] ([] (jt.clock/make (fn [^Clock c] (LocalDate/now c))))) @@ -34,14 +34,14 @@ * no arguments - current local time * one argument - + clock - + another temporal entity - + string representation - + hours + + clock + + another temporal entity + + string representation + + hours * two arguments - + formatter (format) and a string - + an instant and a zone id - + hours and minutes + + formatter (format) and a string + + an instant and a zone id + + hours and minutes * three/four arguments - hour, minute, second, nanos" :returns LocalTime :implicit-arities [1 2 3] @@ -54,17 +54,17 @@ * no arguments - current local date-time * one argument - + clock - + another temporal entity - + string representation - + year + + clock + + another temporal entity + + string representation + + year * two arguments - + local date and local time - + an instant and a zone id - + formatter (format) and a string - + year and month + + local date and local time + + an instant and a zone id + + formatter (format) and a string + + year and month - three and more arguments - year/month/day/..." + * three and more arguments - year/month/day/..." :returns LocalDateTime :implicit-arities [1 2 3] ([] (jt.clock/make (fn [^Clock c] (LocalDateTime/now c)))) @@ -178,4 +178,3 @@ (conversion! CharSequence java.time.format.DateTimeFormatter jt.f/formatter) - diff --git a/src/java_time/mock.clj b/src/java_time/mock.clj index c7c703d..6dcbf25 100644 --- a/src/java_time/mock.clj +++ b/src/java_time/mock.clj @@ -13,6 +13,7 @@ "Returns a mock implementation of the `java.time.Clock`. The mock supports `advance-clock!` operation which allows to move the time in the clock, e.g.: + ``` (let [clock (mock-clock 0 \"UTC\")] (with-clock clock (is (= (value clock) 0)) @@ -20,10 +21,11 @@ (advance-clock! clock (j/millis 1)) (is (= (value clock) 1)) (is (= (instant) (instant 1))))) + ``` You can move the clock back via advancing by a negative temporal amount. - Creates a clock at epoch in the default timezone when called without arguments." + Creates a clock at epoch in the default time zone when called without arguments." ([] (mock-clock 0)) ([instant] (mock-clock instant (zone/zone-id))) ([instant zone] diff --git a/src/java_time/potemkin/namespaces.clj b/src/java_time/potemkin/namespaces.clj deleted file mode 100644 index 0ef11cd..0000000 --- a/src/java_time/potemkin/namespaces.clj +++ /dev/null @@ -1,118 +0,0 @@ -; The MIT License (MIT) -; -; Copyright (c) 2013 Zachary Tellman -; -; Permission is hereby granted, free of charge, to any person obtaining a copy -; of this software and associated documentation files (the "Software"), to deal -; in the Software without restriction, including without limitation the rights -; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -; copies of the Software, and to permit persons to whom the Software is -; furnished to do so, subject to the following conditions: -; -; The above copyright notice and this permission notice shall be included in -; all copies or substantial portions of the Software.) -; -; Copied from https://github.com/ztellman/potemkin/blob/master/src/potemkin/namespaces.clj -; to avoid having a dependency -(ns java-time.potemkin.namespaces) - -(defn link-vars - "Makes sure that all changes to `src` are reflected in `dst`." - [src dst] - (add-watch src dst - (fn [_ src old new] - (alter-var-root dst (constantly @src)) - (alter-meta! dst merge (dissoc (meta src) :name))))) - -(defmacro import-fn - "Given a function in another namespace, defines a function with the - same name in the current namespace. Argument lists, doc-strings, - and original line-numbers are preserved." - ([sym] - `(import-fn ~sym nil)) - ([sym name] - (let [vr (resolve sym) - m (meta vr) - n (or name (:name m)) - arglists (:arglists m) - protocol (:protocol m)] - (when-not vr - (throw (IllegalArgumentException. (str "Don't recognize " sym)))) - (when (:macro m) - (throw (IllegalArgumentException. - (str "Calling import-fn on a macro: " sym)))) - - `(do - (def ~(with-meta n {:protocol protocol}) (deref ~vr)) - (alter-meta! (var ~n) merge (dissoc (meta ~vr) :name)) - (link-vars ~vr (var ~n)) - ~vr)))) - -(defmacro import-macro - "Given a macro in another namespace, defines a macro with the same - name in the current namespace. Argument lists, doc-strings, and - original line-numbers are preserved." - ([sym] - `(import-macro ~sym nil)) - ([sym name] - (let [vr (resolve sym) - m (meta vr) - n (or name (:name m)) - arglists (:arglists m)] - (when-not vr - (throw (IllegalArgumentException. (str "Don't recognize " sym)))) - (when-not (:macro m) - (throw (IllegalArgumentException. - (str "Calling import-macro on a non-macro: " sym)))) - `(do - (def ~n ~(resolve sym)) - (alter-meta! (var ~n) merge (dissoc (meta ~vr) :name)) - (.setMacro (var ~n)) - (link-vars ~vr (var ~n)) - ~vr)))) - -(defmacro import-def - "Given a regular def'd var from another namespace, defined a new var with the - same name in the current namespace." - ([sym] - `(import-def ~sym nil)) - ([sym name] - (let [vr (resolve sym) - m (meta vr) - n (or name (:name m)) - n (if (:dynamic m) (with-meta n {:dynamic true}) n) - nspace (:ns m)] - (when-not vr - (throw (IllegalArgumentException. (str "Don't recognize " sym)))) - `(do - (def ~n @~vr) - (alter-meta! (var ~n) merge (dissoc (meta ~vr) :name)) - (link-vars ~vr (var ~n)) - ~vr)))) - -(defmacro import-vars - "Imports a list of vars from other namespaces." - [& syms] - (let [unravel (fn unravel [x] - (if (sequential? x) - (->> x - rest - (mapcat unravel) - (map - #(symbol - (str (first x) - (when-let [n (namespace %)] - (str "." n))) - (name %)))) - [x])) - syms (mapcat unravel syms)] - `(do - ~@(map - (fn [sym] - (let [vr (resolve sym) - m (meta vr)] - (cond - (:macro m) `(import-macro ~sym) - (:arglists m) `(import-fn ~sym) - :else `(import-def ~sym)))) - syms)))) diff --git a/src/java_time/pre_java8.clj b/src/java_time/pre_java8.clj index 8b26233..a11e783 100644 --- a/src/java_time/pre_java8.clj +++ b/src/java_time/pre_java8.clj @@ -3,22 +3,23 @@ [convert :as jt.c] [local :as jt.l] [temporal :as jt.t] + [util :as jt.u] [defconversion :refer [conversion!]]])) (defn ^java.util.Date java-date "Creates a `java.util.Date` out of any combination of arguments valid for - `java-time/instant` or the Instant itself. + [[instant]] or the Instant itself. A `java.util.Date` represents an instant in time. It's a direct analog of the `java.time.Instant` type introduced in the JSR-310. Please consider using the - `java.time.Instant` (through `java-time/instant`) directly." + `java.time.Instant` (through [[instant]]) directly." ([] (java.util.Date/from (jt.t/instant))) ([a] (java.util.Date/from (jt.t/instant a))) ([a b] (java.util.Date/from (jt.t/instant a b)))) (defn- arities [type ctor n-args] (for [i (range (inc n-args))] - (let [arg-vec (vec (take i (repeatedly gensym))) + (let [arg-vec (mapv #(gensym (str "arg" %)) (range i)) type-ctor (symbol (name type) "valueOf")] `(~arg-vec (~type-ctor (~ctor ~@arg-vec)))))) @@ -35,35 +36,35 @@ (fn [^java.sql.Timestamp dt] (.toLocalDateTime dt))) -(conversion! java.sql.Time java.time.LocalTime - (fn [^java.sql.Time dt] - (.toLocalTime dt))) +(jt.u/when-class "java.sql.Time" + (conversion! java.sql.Time java.time.LocalTime + (fn [^java.sql.Time dt] + (.toLocalTime dt)))) (defsqldate java.sql.Date sql-date jt.l/local-date 3 "Creates a `java.sql.Date` out of any combination of arguments valid for - `java-time/local-date` or the `LocalDate` itself. + [[local-date]] or the `LocalDate` itself. Please consider using the JSR-310 Java Time types instead of `java.sql.Date` if your drivers support them. Even though `java.sql.Date` extends a `java.util.Date`, it's supposed to be - used as a local date (no time component or timezone) for the purposes of + used as a local date (no time component or time zone) for the purposes of conversion from/to native JDBC driver DATE types.") (defsqldate java.sql.Timestamp sql-timestamp jt.l/local-date-time 7 - "Creates a `java.sql.Timestamp` in the local timezone out of any combination - of arguments valid for `java-time/local-date-time` or the `LocalDateTime` + "Creates a `java.sql.Timestamp` in the local time zone out of any combination + of arguments valid for [[local-date-time]] or the `LocalDateTime` itself. - The `sql-timestamp` constructor function does not support `Timestamp` - construction from an `Instant` or a long millis value. Please use - `instant->sql-timestamp` for this purpose. + Does not support `Timestamp` construction from an `Instant` or a long millis value---please use + [[instant->sql-timestamp]] for this purpose. Please consider using the JSR-310 Java Time types instead of `java.sql.Timestamp` if your drivers support them. `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used - as a local date-time (no timezone) for the purposes of conversion from/to native + as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types.") (defn instant->sql-timestamp @@ -74,21 +75,22 @@ `java.sql.Timestamp` if your drivers support them. `java.sql.Timestamp` is a version of a `java.util.Date` supposed to be used - as a local date-time (no timezone) for the purposes of conversion from/to native + as a local date-time (no time zone) for the purposes of conversion from/to native JDBC driver TIMESTAMP types." [instant-or-millis] (if (number? instant-or-millis) (java.sql.Timestamp. (long instant-or-millis)) (java.sql.Timestamp/from (jt.t/instant instant-or-millis)))) -(defsqldate java.sql.Time sql-time jt.l/local-time 3 - "Creates a `java.sql.Time` out of any combination of arguments valid for - `java-time/local-time` (except the nanos constructor) or the `LocalTime` - itself. +(jt.u/when-class "java.sql.Time" + (defsqldate java.sql.Time sql-time jt.l/local-time 3 + "Creates a `java.sql.Time` out of any combination of arguments valid for + [[local-time]] (except the nanos constructor) or the `LocalTime` + itself. - Please consider using the JSR-310 Java Time types instead of `java.sql.Time` - if your drivers support them. + Please consider using the JSR-310 Java Time types instead of `java.sql.Time` + if your drivers support them. - Even though `java.sql.Time` extends a `java.util.Date`, it's supposed to be - used as a local time (no date component or timezone) for the purposes of - conversion from/to native JDBC driver TIME types.") + Even though `java.sql.Time` extends a `java.util.Date`, it's supposed to be + used as a local time (no date component or time zone) for the purposes of + conversion from/to native JDBC driver TIME types.")) diff --git a/src/java_time/properties.clj b/src/java_time/properties.clj index b25ee60..f8df4a8 100644 --- a/src/java_time/properties.clj +++ b/src/java_time/properties.clj @@ -3,8 +3,7 @@ [java-time.util :as jt.u] [java-time.fields :as jt.f] [java-time.units :as jt.units]) - (:import [java.time.temporal - TemporalField TemporalUnit TemporalAccessor Temporal] + (:import [java.time.temporal TemporalField TemporalUnit TemporalAccessor Temporal] (clojure.lang Keyword))) (defn- property->key [p] @@ -68,9 +67,8 @@ (jt.c/unit* *units* o))) (defn ^TemporalUnit get-unit-checked [o] - (if-let [u (get-unit o)] - u - (throw (NullPointerException. (str "No temporal unit found for " o "!"))))) + (or (get-unit o) + (throw (NullPointerException. (str "No temporal unit found for " o "!"))))) (defn unit-key [o] (cond (keyword? o) @@ -126,25 +124,25 @@ (field? o) (property->key o))) -(defn ^TemporalUnit unit +(defn ^java.time.temporal.TemporalUnit unit "Returns a `TemporalUnit` for the given key `k` or extracts the field from the given temporal `entity`. - You can see predefined units via `java-time.repl/show-units`. + You can see predefined units via [[java-time.repl/show-units]]. If you want to make your own custom TemporalUnits resolvable, you need to rebind the - `java-time.properties/*units*` to a custom `java-time.properties.UnitGroup`." + `java-time.properties/*units*` to a custom `java_time.properties.UnitGroup`." ([k] (get-unit k)) ([entity k] (jt.c/unit* entity k))) -(defn ^TemporalField field +(defn ^java.time.temporal.TemporalUnit field "Returns a `TemporalField` for the given key `k` or extracts the field from the given temporal `entity`. - You can see predefined fields via `java-time.repl/show-fields`. + You can see predefined fields via [[java-time.repl/show-fields]]. If you want to make your own custom TemporalFields resolvable, you need to rebind the - `java-time.properties/*fields*` to a custom `java-time.properties.FieldGroup`." + `java-time.properties/*fields*` to a custom `java_time.properties.FieldGroup`." ([k] (get-field k)) ([entity k] (jt.c/field* entity k))) diff --git a/src/java_time/repl.clj b/src/java_time/repl.clj index cd869af..f58bf77 100644 --- a/src/java_time/repl.clj +++ b/src/java_time/repl.clj @@ -4,7 +4,9 @@ [java-time.format :as jt.f] [java-time.zone :as jt.z] [java-time.defconversion :as jt.dc] - [clojure.pprint :as pprint])) + java-time.graph + [clojure.pprint :as pprint]) + (:import [java_time.graph ConversionGraph])) (defn show-adjusters [] (pprint/pprint (sort (keys j.adj/predefined-adjusters)))) @@ -22,7 +24,8 @@ (pprint/pprint (sort (jt.z/available-zone-ids)))) (defn show-graph [] - (pprint/pprint (.m-by-arity @jt.dc/graph))) + (let [^ConversionGraph g @jt.dc/graph] + (pprint/pprint (.m-by-arity g)))) (defn show-path [from to] (jt.dc/get-path from to)) diff --git a/src/java_time/seqs.clj b/src/java_time/seqs.clj index 5e1b908..2d68fbf 100644 --- a/src/java_time/seqs.clj +++ b/src/java_time/seqs.clj @@ -11,14 +11,16 @@ Useful when you want to produce a sequence of temporal entities, for example: - (iterate plus (days 0) 1) - => (# # # ...) + ``` + (iterate plus (days 0) 1) + => (# # # ...) - (iterate plus (local-date 2010 1 1) (years 1)) - => (# # ...) + (iterate plus (local-date 2010 1 1) (years 1)) + => (# # ...) - (iterate adjust (local-date 2010 1 1) :next-working-day) - => (# # ...)" + (iterate adjust (local-date 2010 1 1) :next-working-day) + => (# # ...) + ```" [f initial v & vs] (clojure.core/iterate (apply partialr f v vs) initial)) diff --git a/src/java_time/single_field.clj b/src/java_time/single_field.cljc similarity index 75% rename from src/java_time/single_field.clj rename to src/java_time/single_field.cljc index dd28ca7..6f1ef70 100644 --- a/src/java_time/single_field.clj +++ b/src/java_time/single_field.cljc @@ -10,37 +10,54 @@ [java.time.format DateTimeFormatter] [java.time Clock Year Month YearMonth MonthDay DayOfWeek ZoneId Instant])) +(defn- resolve-tag [tag] + (if (symbol? tag) + (let [cls (resolve tag)] + (if (var? cls) + ;;primitive + tag + (symbol (.getName ^Class cls)))) + tag)) + (defn- get-only-unit-value ^long [^TemporalAmount a, ^TemporalUnit u] (let [non-zero-units (->> (.getUnits a) - (map (fn [^TemporalUnit tu] (vector tu (.get a tu)))) - (filter (fn [[_ uv]] (not (zero? uv))))) + (map (fn [^TemporalUnit tu] [tu (.get a tu)])) + (remove (fn [[_ uv]] (zero? uv)))) [our-unit our-value] (first (filter (fn [[tu]] (= tu u)) non-zero-units))] (when-not our-unit - (throw (java.time.temporal.UnsupportedTemporalTypeException. - (format "No unit: %s found in %s!" u a)))) + (let [msg (format "No unit: %s found in %s!" u a)] + (throw #?(:bb (ex-info msg {}) + :default (java.time.temporal.UnsupportedTemporalTypeException. msg))))) (when (> (count non-zero-units) 1) - (throw (java.time.temporal.UnsupportedTemporalTypeException. - (format "Cannot use: %s, expected only %s to be non-zero!" a u)))) + (let [msg (format "Cannot use: %s, expected only %s to be non-zero!" a u)] + (throw #?(:bb (ex-info msg {}) + :default (java.time.temporal.UnsupportedTemporalTypeException. msg))))) (long our-value))) (defmacro enumerated-entity [tp doc & {:keys [unit]}] - (let [fname (with-meta (symbol (jt.u/dashize (str tp))) {:tag tp}) + (assert (string? doc)) + (let [tp (resolve-tag tp) + fname (with-meta (symbol (jt.u/dashize (-> (str tp) (string/split #"\.") peek))) {:tag tp}) + o (with-meta (gensym 'o) {:tag tp}) fields (symbol (str fname "-fields"))] `(do (def ~fields - (->> (jt.u/get-static-fields-of-type ~tp TemporalAccessor) - (vals) - (map (fn [m#] [(keyword (string/lower-case (str m#))) m#])) - (into {}))) + (->> (jt.u/class->TemporalAccessor-static-fields ~tp) + vals + (into {} (map (fn [m#] [(keyword (string/lower-case (str m#))) m#]))))) - (defn ^{:doc ~(str "True if `" tp "`.")} ~(symbol (str fname "?")) + (defn ~(symbol (str fname "?")) + {:arglists '~'[[o]] + :doc ~(str "True if `" tp "`.")} [o#] (instance? ~tp o#)) (conversion! ~tp Number jt.c/value) - (defn ~fname ~doc + (defn ~fname + {:arglists '~'[[] [v] [fmt arg]] + :doc ~doc} ([] (. ~tp from (jt.z/zoned-date-time))) ([v#] (cond (keyword? v#) (v# ~fields) @@ -55,10 +72,13 @@ (extend-type ~tp jt.c/Ordered - (single-after? [d# o#] - (> (.getValue d#) (.getValue (~fname o#)))) - (single-before? [d# o#] - (< (.getValue d#) (.getValue (~fname o#))))) + (single-after? [d# ~o] + (> (.getValue d#) (.getValue ~o))) + (single-before? [d# ~o] + (< (.getValue d#) (.getValue ~o))) + + jt.c/Convert + (-convert [_# o#] (~fname o#))) ;; Enum-based entities do not implement `Temporal`, thus we don't have an easy ;; option to add/subtract a TemporalAmount. @@ -78,16 +98,23 @@ o# os#))))))))) (defmacro single-field-entity [tp doc & {:keys [parseable?]}] - (let [fname (with-meta (symbol (jt.u/dashize (str tp))) {:tag tp}) + (assert (string? doc)) + (let [^Class tpcls (resolve tp) + tp (symbol (.getName tpcls)) + fname (with-meta (symbol (jt.u/dashize (-> (str tp) (string/split #"\.") peek))) {:tag tp}) + o (with-meta (gensym 'o) {:tag tp}) arg (gensym)] `(do - (defn ^{:doc ~(str "True if `" tp "`.")} ~(symbol (str fname "?")) + (defn ~(symbol (str fname "?")) + {:arglists '~'[[o]] + :doc ~(str "Returns true if `o` is `" tp "`, otherwise false.")} [o#] (instance? ~tp o#)) (conversion! ~tp Number jt.c/value) (defn ~fname ~doc + {:arglists '~'[[] [arg] [fmt arg]]} ([] (. ~tp from (jt.z/zoned-date-time))) ([~arg] (cond (number? ~arg) (. ~tp of (int ~arg)) @@ -111,25 +138,35 @@ (extend-type ~tp jt.c/Ordered - (single-after? [d# o#] - (> (.getValue d#) (.getValue (~fname o#)))) - (single-before? [d# o#] - (< (.getValue d#) (.getValue (~fname o#)))))))) + (single-after? [d# ~o] + (> (.getValue d#) (.getValue ~o))) + (single-before? [d# ~o] + (< (.getValue d#) (.getValue ~o))) + + jt.c/Convert + (-convert [_# o#] (~fname o#)))))) (defmacro two-field-entity [tp doc & {:keys [major-field-types major-field-ctor minor-field-ctor minor-field-default]}] + (assert (string? doc)) (let [[major-field-ctor major-field-type] major-field-ctor [minor-field-ctor minor-field-type] minor-field-ctor - fname (with-meta (symbol (jt.u/dashize (str tp))) {:tag tp}) + major-field-type (resolve-tag major-field-type) + minor-field-type (resolve-tag minor-field-type) + tp (resolve-tag tp) + fname (with-meta (symbol (jt.u/dashize (-> (str tp) (string/split #"\.") peek))) {:tag tp}) arg (gensym) tmp-major (with-meta (gensym) {:tag major-field-type}) tmp-minor (with-meta (gensym) {:tag minor-field-type})] `(do - (defn ^{:doc ~(str "True if `" tp "`.") } ~(symbol (str fname "?")) + (defn ~(symbol (str fname "?")) + {:arglists '~'[[o]] + :doc ~(str "Returns true if `o` is `" tp "`, otherwise false.")} [o#] (instance? ~tp o#)) (defn ~fname ~doc + {:arglists '~'[[] [arg] [a b]]} ([] (. ~tp from (jt.z/zoned-date-time))) ([~arg] (cond (some (fn [x#] (instance? x# ~arg)) ~major-field-types) (let [~tmp-major (~major-field-ctor ~arg)] diff --git a/src/java_time/sugar.clj b/src/java_time/sugar.clj index ed0f53e..2a975c1 100644 --- a/src/java_time/sugar.clj +++ b/src/java_time/sugar.clj @@ -1,5 +1,6 @@ (ns java-time.sugar - (:require [java-time.core :as jt.c] + (:require [clojure.string :as str] + [java-time.core :as jt.c] [java-time.util :as jt.u])) (defmacro gen-sugar-fns @@ -7,7 +8,8 @@ (conj (map (fn [[day-name day-number]] `(defn ~(symbol (str day-name '?)) ~(str "Returns true if the given time entity with the\n" - " `day-of-week` property falls on a " day-name ".") + " `day-of-week` property falls on a " (str/capitalize day-name) ", otherwise false.") + {:arglists '[[~'i]]} [o#] (if-let [p# (jt.c/property o# :day-of-week)] (= (jt.c/value p#) ~day-number) @@ -23,8 +25,13 @@ (gen-sugar-fns) -(defn weekend? [dt] +(defn weekend? + "Returns true if argument is [[saturday?]] or [[sunday?]], + otherwise false." + [dt] (or (saturday? dt) (sunday? dt))) -(defn weekday? [dt] +(defn weekday? + "Complement of [[weekend?]]." + [dt] (not (weekend? dt))) diff --git a/src/java_time/temporal.clj b/src/java_time/temporal.clj index 6d95dc8..6425655 100644 --- a/src/java_time/temporal.clj +++ b/src/java_time/temporal.clj @@ -9,7 +9,6 @@ (:import [java.time.temporal Temporal TemporalAccessor ValueRange TemporalField TemporalUnit TemporalAmount ChronoField IsoFields] [java.time.format DateTimeFormatter] - [java.time.chrono Chronology] [java.time DateTimeException Clock Period Duration MonthDay DayOfWeek Month Year ZoneOffset Instant])) @@ -52,9 +51,8 @@ :get-value-fn-sym getTotalSeconds) (jt.u/when-threeten-extra - (import [org.threeten.extra AmPm DayOfMonth DayOfYear Quarter YearQuarter]) - (value-property DayOfMonth ChronoField/DAY_OF_MONTH) - (value-property DayOfYear ChronoField/DAY_OF_YEAR)) + (value-property org.threeten.extra.DayOfMonth ChronoField/DAY_OF_MONTH) + (value-property org.threeten.extra.DayOfYear ChronoField/DAY_OF_YEAR)) ;;;;; FIELD PROPERTY @@ -67,7 +65,7 @@ (defn- quarter->month [q] (Math/min 12 (Math/max 1 (long (inc (* 3 (dec q))))))) -(defrecord MonthDayFieldProperty [^MonthDay o, ^TemporalField field] +(deftype MonthDayFieldProperty [^MonthDay o, ^TemporalField field] jt.c/WritableProperty (with-value [_ v] (condp = field @@ -76,18 +74,16 @@ IsoFields/QUARTER_OF_YEAR (.withMonth o (quarter->month v))))) (alter-meta! #'->MonthDayFieldProperty assoc :private true) -(alter-meta! #'map->MonthDayFieldProperty assoc :private true) -(defrecord DayOfWeekFieldProperty [^DayOfWeek o, ^TemporalField field] +(deftype DayOfWeekFieldProperty [^DayOfWeek o, ^TemporalField field] jt.c/WritableProperty (with-value [_ v] (condp = field ChronoField/DAY_OF_WEEK (DayOfWeek/of v)))) (alter-meta! #'->DayOfWeekFieldProperty assoc :private true) -(alter-meta! #'map->DayOfWeekFieldProperty assoc :private true) -(defrecord MonthFieldProperty [^Month o, ^TemporalField field] +(deftype MonthFieldProperty [^Month o, ^TemporalField field] jt.c/WritableProperty (with-value [_ v] (condp = field @@ -95,23 +91,20 @@ IsoFields/QUARTER_OF_YEAR (Month/of (quarter->month v))))) (alter-meta! #'->MonthFieldProperty assoc :private true) -(alter-meta! #'map->MonthFieldProperty assoc :private true) -(defrecord ZoneOffsetFieldProperty [^ZoneOffset o, ^TemporalField field] +(deftype ZoneOffsetFieldProperty [^ZoneOffset o, ^TemporalField field] jt.c/WritableProperty (with-value [_ v] (condp = field ChronoField/OFFSET_SECONDS (ZoneOffset/ofTotalSeconds v)))) (alter-meta! #'->ZoneOffsetFieldProperty assoc :private true) -(alter-meta! #'map->ZoneOffsetFieldProperty assoc :private true) -(defrecord TemporalFieldProperty [^Temporal o, ^TemporalField field] +(deftype TemporalFieldProperty [^Temporal o, ^TemporalField field] jt.c/WritableProperty (with-value [_ v] (.with o field v))) (alter-meta! #'->TemporalFieldProperty assoc :private true) -(alter-meta! #'map->TemporalFieldProperty assoc :private true) (defmacro field-property [java-type has-range?] (let [java-type-arg (with-meta (gensym) {:tag java-type})] @@ -176,9 +169,8 @@ res (transient {})] (if f (recur (first r) (rest r) - (if (jt.c/supports? o f) - (assoc! res k f) - res)) + (cond-> res + (jt.c/supports? o f) (assoc! k f))) (persistent! res))))) jt.c/HasProperties @@ -195,7 +187,7 @@ ;;;;;;;;; RANGE -(defn ^ValueRange value-range +(defn ^java.time.temporal.ValueRange value-range "Creates a `ValueRange` given the `min` and `max` amounts or a map of `:min-smallest`, `:max-smallest`, `:min-largest` and `:max-largest`." ([min max] @@ -206,15 +198,14 @@ ;;;;;;;;; AMOUNT -(defrecord TemporalAmountUnitProperty [^TemporalAmount ta, ^TemporalUnit unit] +(deftype TemporalAmountUnitProperty [^TemporalAmount ta, ^TemporalUnit unit] jt.c/ReadableProperty (value [_] (.get ta unit))) (alter-meta! #'->TemporalAmountUnitProperty assoc :private true) -(alter-meta! #'map->TemporalAmountUnitProperty assoc :private true) -(defrecord PeriodUnitProperty [^Period p, unit-key] +(deftype PeriodUnitProperty [^Period p, unit-key] jt.c/ReadableProperty (value [_] (case unit-key @@ -230,9 +221,8 @@ :days (.withDays p v)))) (alter-meta! #'->PeriodUnitProperty assoc :private true) -(alter-meta! #'map->PeriodUnitProperty assoc :private true) -(defrecord DurationUnitProperty [^Duration d, unit-key] +(deftype DurationUnitProperty [^Duration d, unit-key] jt.c/ReadableProperty (value [_] (case unit-key @@ -246,7 +236,6 @@ :nanos (.withNanos d v)))) (alter-meta! #'->DurationUnitProperty assoc :private true) -(alter-meta! #'map->DurationUnitProperty assoc :private true) (def default-unit-property-factory (reify PropertyFactory @@ -261,12 +250,12 @@ (extend-type TemporalAmount jt.c/Supporting (supports? [o k] - (not (nil? (jt.c/unit* o (jt.p/get-unit k))))) + (some? (jt.c/unit* o (jt.p/get-unit k)))) jt.c/HasUnits (unit* [o k] (when-let [u (jt.p/get-unit k)] - (first (filter #(= u %) (.getUnits o))))) + (some #{u} (.getUnits o)))) (units [o] (let [[u & us] (.getUnits o)] @@ -312,7 +301,7 @@ jt.c/KnowsIfLeap (leap? [o] (when-let [year (-> (jt.c/property o :year) - (jt.c/value))] + jt.c/value)] (if (satisfies? jt.c/HasChronology o) (.isLeapYear (jt.c/chronology o) year) (Year/isLeap year)))) @@ -331,9 +320,10 @@ (fn [^java.util.Date dt] (.toInstant dt))) -(conversion! java.util.Calendar Instant - (fn [^java.util.Calendar c] - (.toInstant c))) +(jt.u/when-class "java.util.Calendar" + (conversion! java.util.Calendar Instant + (fn [^java.util.Calendar c] + (.toInstant c)))) (conversion! CharSequence Instant (fn [^CharSequence s] @@ -352,13 +342,13 @@ * no arguments - current instant * one argument - + clock - + java.util.Date/Calendar - + another temporal entity - + string representation - + millis from epoch + + clock + + java.util.Date/Calendar + + another temporal entity + + string representation + + millis from epoch * two arguments - + formatter (format) and a string" + + formatter (format) and a string" :returns Instant :implicit-arities [1 2] ([] (jt.clock/make #(Instant/now %)))) @@ -370,6 +360,17 @@ jt.c/Ordered (single-after? [d o] - (.isAfter d o)) + (if (jt.u/when-threeten-extra + (instance? org.threeten.extra.Interval o)) + (jt.u/when-threeten-extra + ;; end is exclusive + ;; d >= (end o) + (>= (.compareTo d (.getEnd ^org.threeten.extra.Interval o)) + 0)) + (.isAfter d o))) (single-before? [d o] - (.isBefore d o))) + (if (jt.u/when-threeten-extra + (instance? org.threeten.extra.Interval o)) + (jt.u/when-threeten-extra + (.isBefore d (.getStart ^org.threeten.extra.Interval o))) + (.isBefore d o)))) diff --git a/src/java_time/util.clj b/src/java_time/util.clj deleted file mode 100644 index 67f178d..0000000 --- a/src/java_time/util.clj +++ /dev/null @@ -1,57 +0,0 @@ -(ns java-time.util - (:require [clojure.string :as string]) - (:import [java.lang.reflect Field])) - -(defn get-static-fields-of-type [^Class klass, ^Class of-type] - (->> (seq (.getFields klass)) - (map (fn [^Field f] - (when (.isAssignableFrom of-type (.getType f)) - [(.getName f) (.get f nil)])) ) - (keep identity) - (into {}))) - -(defn dashize [camelcase] - (let [words (re-seq #"([^A-Z]+|[A-Z]+[^A-Z]*)" camelcase)] - (string/join "-" (map (comp string/lower-case first) words)))) - -(defmacro if-threeten-extra [then-body else-body] - (if (try (Class/forName "org.threeten.extra.Temporals") - (catch Throwable e)) - `(do ~then-body) - `(do ~else-body))) - -(defmacro when-threeten-extra [& body] - (if (try (Class/forName "org.threeten.extra.Temporals") - (catch Throwable e)) - `(do ~@body))) - -(defmacro when-joda-time-loaded - "Execute the `body` when Joda-Time classes are found on the classpath. - - Take care - when AOT-compiling code using this macro, the Joda-Time classes - must be on the classpath at compile time!" - [& body] - (if (try (Class/forName "org.joda.time.DateTime") - (catch Throwable e)) - `(do ~@body))) - -;; From Medley, C Weavejester -(defn editable? [coll] - (instance? clojure.lang.IEditableCollection coll)) - -(defn reduce-map [f coll] - (if (editable? coll) - (persistent! (reduce-kv (f assoc!) (transient (empty coll)) coll)) - (reduce-kv (f assoc) (empty coll) coll))) - -(defn map-vals - "Maps a function over the values of an associative collection." - [f coll] - (reduce-map (fn [xf] (fn [m k v] (xf m k (f v)))) coll)) - -(defn map-kv - "Maps a function over the key/value pairs of an associate collection. Expects - a function that takes two arguments, the key and value, and returns the new - key and value as a collection of two elements." - [f coll] - (reduce-map (fn [xf] (fn [m k v] (let [[k v] (f k v)] (xf m k v)))) coll)) diff --git a/src/java_time/util.cljc b/src/java_time/util.cljc new file mode 100644 index 0000000..d70fafe --- /dev/null +++ b/src/java_time/util.cljc @@ -0,0 +1,96 @@ +(ns java-time.util + (:require [clojure.string :as string])) + +(defn ^:deprecated get-static-fields-of-type + [^Class klass, ^Class of-type] + (->> (seq (.getFields klass)) + (map (fn [^java.lang.reflect.Field f] + (when (.isAssignableFrom of-type (.getType f)) + [(.getName f) (.get f nil)])) ) + (keep identity) + (into {}))) + +(defn dashize [camelcase] + (let [words (re-seq #"([^A-Z]+|[A-Z]+[^A-Z]*)" camelcase)] + (string/join "-" (map (comp string/lower-case first) words)))) + +(defmacro if-class [clstr then else] + (let [loaded (try (Class/forName clstr) + (catch Throwable e))] + (if #?(:bb (and (resolve (symbol clstr)) loaded) + :default loaded) + then + else))) + +(defmacro when-class [clstr & body] + `(if-class ~clstr (do ~@body) nil)) + +(defmacro if-threeten-extra [then-body else-body] + `(if-class "org.threeten.extra.Temporals" + ~then-body + ~else-body)) + +(defmacro when-threeten-extra [& body] + `(if-threeten-extra (do ~@body) nil)) + +(defmacro when-joda-time-loaded + "Execute the `body` when Joda-Time classes are found on the classpath. + + Take care - when AOT-compiling code using this macro, the Joda-Time classes + must be on the classpath at compile time!" + [& body] + (if (try (Class/forName "org.joda.time.DateTime") + (catch Throwable e)) + `(do ~@body))) + +;; From Medley, C Weavejester +(defn editable? [coll] + (instance? clojure.lang.IEditableCollection coll)) + +(defn reduce-map [f coll] + (if (editable? coll) + (persistent! (reduce-kv (f assoc!) (transient (empty coll)) coll)) + (reduce-kv (f assoc) (empty coll) coll))) + +(defn map-vals + "Maps a function over the values of an associative collection." + [f coll] + (reduce-map (fn [xf] (fn [m k v] (xf m k (f v)))) coll)) + +(defn map-kv + "Maps a function over the key/value pairs of an associate collection. Expects + a function that takes two arguments, the key and value, and returns the new + key and value as a collection of two elements." + [f coll] + (reduce-map (fn [xf] (fn [m k v] (let [[k v] (f k v)] (xf m k v)))) coll)) + +(defn class->TemporalAccessor-static-fields [^Class klass] + {:pre [(class? klass)]} + (case (.getName klass) + "java.time.Month" {"JUNE" java.time.Month/JUNE + "DECEMBER" java.time.Month/DECEMBER + "SEPTEMBER" java.time.Month/SEPTEMBER + "OCTOBER" java.time.Month/OCTOBER + "FEBRUARY" java.time.Month/FEBRUARY + "MAY" java.time.Month/MAY + "AUGUST" java.time.Month/AUGUST + "MARCH" java.time.Month/MARCH + "JANUARY" java.time.Month/JANUARY + "JULY" java.time.Month/JULY + "APRIL" java.time.Month/APRIL + "NOVEMBER" java.time.Month/NOVEMBER} + "java.time.DayOfWeek" {"MONDAY" java.time.DayOfWeek/MONDAY + "TUESDAY" java.time.DayOfWeek/TUESDAY + "WEDNESDAY" java.time.DayOfWeek/WEDNESDAY + "THURSDAY" java.time.DayOfWeek/THURSDAY + "FRIDAY" java.time.DayOfWeek/FRIDAY + "SATURDAY" java.time.DayOfWeek/SATURDAY + "SUNDAY" java.time.DayOfWeek/SUNDAY} + "org.threeten.extra.AmPm" (if-threeten-extra + {"AM" org.threeten.extra.AmPm/AM, "PM" org.threeten.extra.AmPm/PM} + (throw (ex-info "org.threeten.extra.AmPm not found"))) + "org.threeten.extra.Quarter" (if-threeten-extra + {"Q1" org.threeten.extra.Quarter/Q1, "Q2" org.threeten.extra.Quarter/Q2, "Q3" org.threeten.extra.Quarter/Q3, "Q4" org.threeten.extra.Quarter/Q4} + (throw (ex-info "org.threeten.extra.Quarter not found"))) + (throw (ex-info (str "TODO class->TemporalAccessor-static-fields " klass) + {})))) diff --git a/src/java_time/zone.clj b/src/java_time/zone.clj index b6367e4..334b632 100644 --- a/src/java_time/zone.clj +++ b/src/java_time/zone.clj @@ -1,5 +1,5 @@ (ns java-time.zone - (:require [java-time.core :as jt.c :refer (value)] + (:require [java-time.core :as jt.c] [java-time.temporal :as jt.t] [java-time.util :as jt.u] [java-time.amount :as jt.a] @@ -93,19 +93,19 @@ * no arguments - current date-time with the default offset * one argument - + clock - + zone offset - + another temporal entity - + string representation - + year + + clock + + zone offset + + another temporal entity + + string representation + + year * two arguments - + formatter (format) and a string - + local date-time and an offset - + another temporal entity and an offset (preserves local time) - + year and month + + formatter (format) and a string + + local date-time and an offset + + another temporal entity and an offset (preserves local time) + + year and month * three arguments - + local date, local time and an offset - + year, month and date + + local date, local time and an offset + + year, month and date * four up to seven arguments - position date-time constructors * eight arguments - time fields up to nanoseconds and a zone offset @@ -120,7 +120,7 @@ ([y mo d h m s n] (offset-date-time y mo d h m s n (zone-offset))) ([y mo d h m s n o] (OffsetDateTime/of - (int (value y)) (int (value mo)) (int (value d)) + (int (jt.c/value y)) (int (jt.c/value mo)) (int (jt.c/value d)) (int h) (int m) (int s) (int n) (zone-offset o)))) (deffactory offset-time @@ -128,16 +128,16 @@ * no arguments - current time with the default offset * one argument - + clock - + zone id - + another temporal entity - + string representation - + hour + + clock + + zone id + + another temporal entity + + string representation + + hour * two arguments - + formatter (format) and a string - + local time and an offset - + instant and an offset - + hour and minutes + + formatter (format) and a string + + local time and an offset + + instant and an offset + + hour and minutes * three arguments - hours, minutes, seconds * four arguments - hours, minutes, seconds, nanos * five arguments - last is the offset @@ -157,18 +157,18 @@ * no arguments - current date-time in the default zone * one argument - + clock - + zone id - + another temporal entity - + string representation - + year + + clock + + zone id + + another temporal entity + + string representation + + year * two arguments - + formatter and a string - + local date-time and a zone id - + year and month + + formatter and a string + + local date-time and a zone id + + year and month * three arguments - + local date, local time and a zone id - + year, month and day + + local date, local time and a zone id + + year, month and day * four to seven arguments - date-time fields * eight arguments - last is the zone id @@ -183,7 +183,7 @@ ([y mo d h m s n] (zoned-date-time y mo d h m s n (zone-id))) ([y mo d h m s n o] (ZonedDateTime/of - (int (value y)) (int (value mo)) (int (value d)) + (int (jt.c/value y)) (int (jt.c/value mo)) (int (jt.c/value d)) (int h) (int m) (int s) (int n) (zone-id o)))) (conversion! Clock ZonedDateTime @@ -200,17 +200,23 @@ (conversion! ZoneId ZonedDateTime (fn [^ZoneId z] - (ZonedDateTime/now z)) + (jt.clock/make + (fn [^Clock c] + (ZonedDateTime/now (.withZone c z))))) 2) (conversion! ZoneId OffsetDateTime (fn [^ZoneId z] - (OffsetDateTime/now z)) + (jt.clock/make + (fn [^Clock c] + (OffsetDateTime/now (.withZone c z))))) 2) (conversion! ZoneId OffsetTime (fn [^ZoneId z] - (OffsetTime/now z)) + (jt.clock/make + (fn [^Clock c] + (OffsetTime/now (.withZone c z))))) 2) (conversion! CharSequence ZonedDateTime @@ -310,9 +316,10 @@ (fn [y m d] (offset-date-time y m d 0))) -(conversion! java.util.GregorianCalendar ZonedDateTime - (fn [^java.util.GregorianCalendar cal] - (.toZonedDateTime cal))) +(jt.u/when-class "java.util.GregorianCalendar" + (conversion! java.util.GregorianCalendar ZonedDateTime + (fn [^java.util.GregorianCalendar cal] + (.toZonedDateTime cal)))) (defprotocol HasOffset (with-offset [o offset] @@ -386,26 +393,26 @@ ;;;;; Clock -(defn ^Clock system-clock - "Creates a system clock. In the default timezone if called without arguments, +(defn ^java.time.Clock system-clock + "Creates a system clock. In the default time zone if called without arguments, otherwise accepts a Zone Id." ([] (Clock/systemDefaultZone)) ([k] (Clock/system (zone-id k)))) -(defn ^Clock fixed-clock +(defn ^java.time.Clock fixed-clock "Creates a fixed clock either at the current instant or at the supplied instant/instant + zone." ([] (Clock/fixed (Instant/now) (zone-id))) ([i] (Clock/fixed (jt.t/instant i) (zone-id))) ([i z] (Clock/fixed (jt.t/instant i) (zone-id z)))) -(defn ^Clock offset-clock +(defn ^java.time.Clock offset-clock "Creates a clock offset from the current/provided clock by a given `duration`." ([d] (Clock/offset (system-clock) (jt.a/duration d))) ([^Clock c, d] (Clock/offset c (jt.a/duration d)))) -(defn ^Clock tick-clock +(defn ^java.time.Clock tick-clock "Creates a clock wrapping system/provided clock that only ticks as per specified duration." ([d] (Clock/tick (system-clock) (jt.a/duration d))) diff --git a/test/java_time/api_test.clj b/test/java_time/api_test.clj new file mode 100644 index 0000000..1fffac2 --- /dev/null +++ b/test/java_time/api_test.clj @@ -0,0 +1,1134 @@ +(ns java-time.api-test + "Shares tests with java-time-test. Don't + add requires or imports to the ns form---only + set the meaning of namespace alias j." + (:require [java-time.api :as j])) + +;; share with java-time-test +(require '[clojure.test :refer :all] + '[java-time.util :as jt.u] + '[java-time.test-utils :refer [is-antisymmetric + is-asymmetric]]) +(import java.util.Locale) + +(def ^java.time.Clock clock (j/fixed-clock "2015-11-26T10:20:30.000000040Z" "UTC")) + +(deftest constructors-test + (testing "clocks" + (testing ", with-clock" + (is (= (j/with-clock clock (j/zone-offset)) + (j/with-clock-fn clock j/zone-offset) + (j/zone-offset clock))) + (are [f] (= (j/with-clock clock (f)) + (j/with-clock clock (f (j/zone-id "UTC"))) + (j/with-clock-fn clock f) + (f clock)) + j/zoned-date-time + j/offset-date-time + j/offset-time + j/local-date-time + j/local-time + j/local-date + j/zone-id) + (doseq [offset ["+01:00" "-01:00"]] + (testing offset + (are [f] (= (j/with-clock clock (f (j/zone-id offset))) + (f (.withZone clock (j/zone-id offset)))) + j/zoned-date-time + j/offset-date-time + j/offset-time + j/local-date-time + j/local-time + j/local-date + j/zone-id)))) + + (testing ", system" + (let [now-millis (j/value (j/system-clock))] + (is (<= now-millis + (j/value (j/system-clock "UTC")))) + (is (= (j/system-clock "UTC") + (j/with-zone (j/system-clock "Europe/Zurich") "UTC"))))) + + (testing ", fixed" + (is (= (j/value (j/fixed-clock "2015-01-01T10:20:30Z" "UTC")) + (j/value (j/fixed-clock "2015-01-01T10:20:30Z"))))) + + (testing ", offset" + (is (= (str (-> (j/fixed-clock "2015-01-01T10:20:30Z" "UTC") + (j/offset-clock (j/minutes 30)))) + "OffsetClock[FixedClock[2015-01-01T10:20:30Z,UTC],PT30M]"))) + + (testing ", tick" + (is (= (str (-> (j/fixed-clock "2015-01-01T10:20:30Z" "UTC") + (j/tick-clock (j/minutes 10)))) + "TickClock[FixedClock[2015-01-01T10:20:30Z,UTC],PT10M]")))) + + (testing "offsets" + (is (= (j/zone-offset +0) + (j/zone-offset "+00:00") + (j/zone-offset -0) + (j/zone-offset 0 0))) + + (is (= (j/zone-offset 1 30) + (j/zone-offset "+01:30") + (j/zone-offset 1 30 0) + (j/zone-offset +1.5)))) + + (testing "enums" + (is (= (j/month 11) + (j/month :november) + (j/month (j/local-date clock)) + (j/month "MM" "11"))) + + (is (j/month? (j/month 7))) + + (is (= (j/day-of-week 4) + (j/day-of-week :thursday) + (j/day-of-week (j/local-date clock)))) + + (is (j/day-of-week? (j/day-of-week 4)))) + + (testing "multi field" + (is (= (j/month-day (j/local-date clock)) + (j/month-day 11 26) + (j/month-day "dd-MM" "26-11"))) + + (is (= (j/month-day 1) + (j/month-day (j/month 1)) + (j/month-day 1 1) + (j/month-day 1 (j/day-of-week 1)))) + + (is (j/month-day? (j/month-day 1 1))) + + (is (= (j/year-month (j/local-date clock)) + (j/year-month 2015 11) + (j/year-month "yy-MM" "15-11"))) + + (is (= (j/year-month 1) + (j/year-month (j/year 1)) + (j/year-month 1 1) + (j/year-month 1 (j/month 1)))) + + (is (j/year-month? (j/year-month 1 1)))) + + (testing "years" + (is (= (j/year clock) + (j/year "2015") + (j/year 2015) + (j/year "yy" "15"))) + + (is (= (j/year "UTC") + (j/year (j/zone-id "UTC")))) + + (is (j/year? (j/year 2015)))) + + (testing "local date" + (is (= (j/local-date clock) + (j/local-date 2015 11 26) + (j/local-date "2015-11-26") + (j/local-date "yyyy/MM/dd" "2015/11/26") + (j/local-date (j/local-date 2015 11 26)) + (j/local-date (j/local-date-time clock)) + (j/local-date (j/zoned-date-time clock)) + (j/local-date (j/offset-date-time clock)) + (j/local-date (j/instant clock) "UTC") + (j/local-date (j/to-java-date clock) "UTC"))) + + (is (j/local-date? (j/local-date))) + + (is (= (j/local-date 2015) + (j/local-date 2015 1) + (j/local-date 2015 1 1) + (j/local-date (j/year 2015) (j/month 1)) + (j/local-date (j/year 2015) (j/month 1) (j/day-of-week 1))))) + + (testing "local time" + (is (= (j/local-time clock) + (j/local-time 10 20 30 40) + (j/local-time "10:20:30.000000040") + (j/local-time "HH:mm,ss:SSSSSSSSS" "10:20,30:000000040") + (j/local-time (j/local-time clock)) + (j/local-time (j/local-date-time clock)) + (j/local-time (j/zoned-date-time clock)) + (j/local-time (j/offset-date-time clock)) + (j/local-time (j/instant clock) "UTC"))) + + (is (= (j/truncate-to (j/local-time clock) :millis) + (j/local-time (j/to-java-date clock) "UTC"))) + + (is (j/local-time? (j/local-time))) + + (is (= (j/local-time 10) + (j/local-time 10 0) + (j/local-time 10 0 0) + (j/local-time 10 0 0 0))) + + (is (= (j/truncate-to (j/local-time 10 20 30 40) :minutes) + (j/local-time 10 20)))) + + (testing "local date time" + (is (= (j/local-date-time clock) + (j/local-date-time 2015 11 26 10 20 30 40) + (j/local-date-time "2015-11-26T10:20:30.000000040") + (j/local-date-time "yyyy/MM/dd'T'SSSSSSSSS,HH:mm:ss" "2015/11/26T000000040,10:20:30") + (j/local-date-time (j/local-date 2015 11 26) (j/local-time 10 20 30 40)) + (j/local-date-time (j/local-date-time clock)) + (j/local-date-time (j/zoned-date-time clock)) + (j/local-date-time (j/offset-date-time clock)) + (j/local-date-time (j/instant clock) "UTC"))) + + (is (= (j/truncate-to (j/local-date-time clock) :millis) + (j/local-date-time (j/to-java-date clock) "UTC"))) + + (is (j/local-date-time? (j/local-date-time))) + + (is (= (j/local-date-time 2015) + (j/local-date-time 2015 1) + (j/local-date-time 2015 1 1) + (j/local-date-time (j/year 2015) (j/month 1)) + (j/local-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) + (j/local-date-time 2015 1 1 0) + (j/local-date-time 2015 1 1 0 0) + (j/local-date-time 2015 1 1 0 0 0) + (j/local-date-time 2015 1 1 0 0 0 0))) + + (is (= (j/truncate-to (j/local-date-time 2015 1 1 10 20 30 40) :minutes) + (j/local-date-time 2015 1 1 10 20)))) + + (testing "zoned date time" + (is (= (j/zoned-date-time clock) + (j/zoned-date-time (j/zoned-date-time clock)) + (j/zoned-date-time "2015-11-26T10:20:30.000000040+00:00[UTC]") + (j/zoned-date-time "2015-11-26T10:20:30.000000040Z[UTC]") + (j/zoned-date-time "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['VV']'" "2015/11/26T10:20:30-000000040[UTC]") + (j/zoned-date-time (j/local-date clock) (j/local-time clock) "UTC") + (j/zoned-date-time (j/local-date-time clock) "UTC") + (j/zoned-date-time (j/offset-date-time clock) "UTC") + (j/zoned-date-time 2015 11 26 10 20 30 40 "UTC") + (j/zoned-date-time (j/instant clock) "UTC"))) + + (is (= (j/truncate-to (j/zoned-date-time clock) :millis) + (j/zoned-date-time (j/to-java-date clock) "UTC"))) + + (is (j/zoned-date-time? (j/zoned-date-time (j/zone-id "UTC")))) + + (j/with-clock (j/system-clock "UTC") + (is (= (j/zoned-date-time 2015) + (j/zoned-date-time 2015 1) + (j/zoned-date-time 2015 1 1) + (j/zoned-date-time (j/year 2015)) + (j/zoned-date-time (j/year 2015) (j/month 1)) + (j/zoned-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) + (j/zoned-date-time 2015 1 1 0) + (j/zoned-date-time 2015 1 1 0 0) + (j/zoned-date-time 2015 1 1 0 0 0) + (j/zoned-date-time 2015 1 1 0 0 0 0)))) + + (let [zone-id (j/zone-id)] + (is (= (j/zoned-date-time 2015 1 1 0 0 0 0) + (j/zoned-date-time 2015 1 1 0 0 0 0 zone-id)))) + + (let [utc (j/zoned-date-time 2015 1 1 0 0 0 0 "UTC")] + (is (= (j/zoned-date-time 2014 12 31 19 0 0 0 "America/New_York") + (j/with-zone-same-instant utc "America/New_York") + (j/with-zone (j/zoned-date-time 2014 12 31 19 0 0 0 "UTC") "America/New_York")))) + + (is (= (j/truncate-to (j/zoned-date-time 2015 1 1 10 20 30 40) :minutes) + (j/zoned-date-time 2015 1 1 10 20)))) + + (testing "offset date time" + (is (= (j/offset-date-time clock) + (j/offset-date-time (j/offset-date-time clock)) + (j/offset-date-time "2015-11-26T10:20:30.000000040+00:00") + (j/offset-date-time "2015-11-26T10:20:30.000000040Z") + (j/offset-date-time "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['X']'" "2015/11/26T10:20:30-000000040[Z]") + (j/offset-date-time (j/local-date clock) (j/local-time clock) (j/zone-offset +0)) + (j/offset-date-time (j/local-date-time clock) (j/zone-offset +0)) + (j/offset-date-time (j/zoned-date-time clock) (j/zone-offset +0)) + (j/offset-date-time 2015 11 26 10 20 30 40 (j/zone-offset +0)) + (j/offset-date-time (j/instant clock) "UTC"))) + + (is (= (j/truncate-to (j/offset-date-time clock) :millis) + (j/offset-date-time (j/to-java-date clock) "UTC"))) + + (is (j/offset-date-time? (j/offset-date-time))) + (is (not (j/offset-date-time? nil))) + + (j/with-clock (j/system-clock "UTC") + (is (= (j/offset-date-time 2015) + (j/offset-date-time 2015 1) + (j/offset-date-time 2015 1 1) + (j/offset-date-time (j/year 2015)) + (j/offset-date-time (j/year 2015) (j/month 1)) + (j/offset-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) + (j/offset-date-time 2015 1 1 0) + (j/offset-date-time 2015 1 1 0 0) + (j/offset-date-time 2015 1 1 0 0 0) + (j/offset-date-time 2015 1 1 0 0 0 0 (j/zone-offset +0))))) + + (is (= (j/truncate-to (j/offset-date-time 2015 1 1 10 20 30 40) :minutes) + (j/offset-date-time 2015 1 1 10 20))) + + (let [utc (j/offset-date-time 2015 1 1 0 0 0 0 +0)] + (is (= (j/offset-date-time 2014 12 31 19 0 0 0 -5) + (j/with-offset-same-instant utc -5) + (j/with-offset (j/offset-date-time 2014 12 31 19 0 0 0 +0) -5))))) + + (testing "offset time" + (is (= (j/offset-time clock) + (j/offset-time (j/offset-time clock)) + (j/offset-time (j/zoned-date-time clock)) + (j/offset-time "10:20:30.000000040+00:00") + (j/offset-time "10:20:30.000000040Z") + (j/offset-time "HH:mm:ss-SSSSSSSSS'['X']'" "10:20:30-000000040[Z]") + (j/offset-time (j/local-time clock) (j/zone-offset +0)) + (j/offset-time (j/instant clock) "UTC") + (j/offset-time 10 20 30 40 +0) + (j/offset-time (j/instant clock) "UTC"))) + + (is (= (j/truncate-to (j/offset-time clock) :millis) + (j/offset-time (j/to-java-date clock) "UTC"))) + + (is (j/offset-time? (j/offset-time (j/zone-id "UTC")))) + (is (j/offset-time? (j/offset-time +0))) + + (j/with-clock (j/system-clock "UTC") + (is (= (j/offset-time 0) + (j/offset-time 0 0) + (j/offset-time 0 0 0) + (j/offset-time 0 0 0 0)))) + + (is (= (j/truncate-to (j/offset-time 10 20 30 40) :minutes) + (j/offset-time 10 20))) + + (let [utc (j/offset-time 15 0 0 0 +0)] + (is (= (j/offset-time 10 0 0 0 -5) + (j/with-offset-same-instant utc -5) + (j/with-offset (j/offset-time 10 0 0 0 +0) -5))))) + + (testing "instant" + (is (= (j/instant clock) + (j/instant "2015-11-26T10:20:30.000000040Z") + (j/instant "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['X']'" "2015/11/26T10:20:30-000000040[Z]"))) + + (is (= (j/truncate-to (j/instant clock) :millis) + ;; (.toEpochMilli instant) + (j/instant 1448533230000)))) + + (testing "duration" + (is (= (j/duration 100) + (j/duration (j/duration 100)) + (j/duration "PT0.1S") + (j/duration (j/local-time 0 0 0 0) (j/local-time 0 0 0 (* 100 1000 1000))) + (j/duration 100 :millis))) + + (is (j/duration? (j/duration)))) + + (testing "period" + (is (= (j/period 10 20 30) + (j/period "P10Y20M30D"))) + + (is (= (j/period 11 9) + (j/period (j/local-date 2001 1 1) (j/local-date 2012 10 1)))) + + (is (= (j/period) + (j/period 0) + (j/period 0 0) + (j/period 0 0 0) + (j/period 0 :years) + (j/period 0 :months) + (j/period 0 :days))) + + (is (j/period? (j/period))) + (is (not (j/period? nil))))) + +(deftest operations-test + (testing "duration" + (is (j/duration? (j/duration 1 :days))) + (is (not (j/duration? nil))) + (testing "plus" + (is (= (j/duration 100000001) + (j/+ (j/standard-days 1) (j/hours 3) (j/minutes 46) (j/seconds 40) (j/millis 1) (j/nanos 0)) + (j/+ (j/duration 1 :days) + (j/duration 3 :hours) + (j/duration 46 :minutes) + (j/duration 40 :seconds) + (j/duration 1 :millis) + (j/duration 0 :nanos))))) + + (testing "minus" + (is (= (j/duration "PT22H58M58.998999999S") + (j/- (j/standard-days 1) (j/hours 1) (j/minutes 1) (j/seconds 1) (j/millis 1) (j/nanos 1))))) + + (testing "multiply" + (is (= (j/hours 2) + (j/multiply-by (j/hours 1) 2)))) + + (testing "number ops" + (is (j/zero? (j/duration 0))) + (is (not (j/zero? (j/duration 10)))) + (is (= (j/duration 10) (j/abs (j/duration -10)))) + (is (= (j/duration -10) (j/negate (j/duration 10)))) + (is (= (j/duration 10) (j/min (j/duration 10) (j/duration 11) (j/duration 12)))) + (is (= (j/duration 12) (j/max (j/duration 10) (j/duration 11) (j/duration 12)))) + (is (j/negative? (j/duration -10))) + (is (not (j/negative? (j/duration 10)))))) + + (testing "period" + (testing "plus" + (is (= (j/period 10 20 30) + (j/+ (j/years 10) (j/months 20) (j/days 30)) + (j/+ (j/period 10) + (j/period 0 20) + (j/period 0 0 30)) + (j/+ (j/period 10 :years) + (j/period 20 :months) + (j/period 30 :days))))) + + (testing "minus" + (is (= (j/period 0 0 0) + (j/- (j/period 10 20 30) (j/years 10) (j/months 20) (j/days 30))))) + + (testing "multiply" + (is (= (j/days 2) + (j/multiply-by (j/days 1) 2)))) + + (testing "number ops" + (is (j/zero? (j/period 0))) + (is (= (j/period -10 10) (j/negate (j/period 10 -10)))) + (is (j/negative? (j/period -10))) + (is (j/negative? (j/period -10 10))))) + + (testing "year" + (testing "plus" + (is (= (j/year 5) + (j/+ (j/year 2) (j/years 3))))) + + (testing "minus" + (is (= (j/year 0) + (j/- (j/year 5) (j/years 5)))))) + + (testing "month" + (testing "plus" + (is (= (j/month :may) + (j/+ (j/month 2) 3) + (j/+ (j/month 2) (j/months 3))))) + + (testing "minus" + (is (= (j/month :january) + (j/- (j/month 5) 4) + (j/- (j/month 5) (j/months 4)))))) + + (testing "day of week" + (testing "plus" + (is (= (j/day-of-week :sunday) + (j/+ (j/day-of-week 1) 6) + (j/+ (j/day-of-week 1) (j/days 6))))) + + (testing "minus" + (is (= (j/day-of-week :monday) + (j/- (j/day-of-week 6) 5) + (j/- (j/day-of-week 6) (j/days 5))))))) + +(deftest aliases-test + (is (= j/before? j/<)) + (is (= j/not-after? j/<=)) + (is (= j/after? j/>)) + (is (= j/not-before? j/>=)) + (is (= j/plus j/+)) + (is (= j/minus j/-))) + +(defmacro is-<-coerce + [a b c a' b' c'] + (assert ((every-pred symbol?) a b c)) + (assert ((every-pred (some-fn number? keyword?)) a' b' c')) + `(do (is (j/> ~b ~a')) + (is (not (j/> ~a ~b'))) + (is (j/< ~b ~c')) + (is (not (j/< ~c ~b'))) + (is (j/<= ~b ~c')) + (is (j/<= ~b ~b')) + (is (not (j/<= ~c ~b'))) + (is (j/>= ~b ~b')) + (is (j/= ~b ~b')) + (is (not (j/= ~b ~a'))) + (is (j/= ~b ~b' ~b)) + (is (j/= ~b ~b' ~b)) + (is (j/= ~b ~b' ~b' ~b ~b)) + (is (not (j/= ~b ~b' ~a' ~b ~b))) + (is (j/>= ~b ~a')) + (is (not (j/>= ~a ~b'))) + (is (j/<= ~a ~a' ~b' ~b ~c ~c')) + (is (not (j/>= ~a ~a' ~b' ~b ~c ~c'))) + (is (j/>= ~c ~c' ~b' ~b ~a ~a')) + (is (j/< ~a ~b' ~c)) + (is (j/< ~a ~b ~c')) + (is (j/< ~a ~b' ~c')) + (is (not (j/< ~a ~c' ~b))) + (is (not (j/< ~a ~c ~b'))) + (is (not (j/< ~a ~c' ~b'))) + (is (j/> ~c ~b' ~a)) + (is (j/> ~c ~b ~a')) + (is (j/> ~c ~b' ~a')) + (is (not (j/> ~c ~a' ~b))) + (is (not (j/> ~c ~a ~b'))) + (is (not (j/> ~c ~a' ~b'))))) + +(defmacro is-< [a b c] + (assert ((every-pred symbol?) a b c)) + `(do (is (j/> ~a)) + (is (j/< ~a)) + (is-asymmetric (j/> ~b ~a)) + (is-asymmetric (j/< ~a ~b)) + (is-asymmetric (j/> ~c ~b ~a)) + (is-asymmetric (j/< ~a ~b ~c)) + (is (j/<= ~a)) + (is (j/>= ~a)) + (is-antisymmetric (j/<= ~a ~a)) + (is-antisymmetric (j/<= ~a ~b)) + (is-antisymmetric (j/>= ~a ~a)) + (is-antisymmetric (j/>= ~b ~a)) + (is-antisymmetric (j/<= ~a ~b ~c)) + (is-antisymmetric (j/>= ~c ~b ~a)) + (is-antisymmetric (j/<= ~a ~a ~b ~b ~c ~c)) + (is-antisymmetric (j/>= ~c ~c ~b ~b ~a ~a)) + (is (j/= ~c)) + (is (j/= ~c ~c)) + (is (j/= ~c ~c ~c)) + (is (j/= ~c ~c ~c ~c)) + (is (not (j/= ~c ~c ~b ~c ~c))))) + +(deftest ordering-test + (testing "times" + (let [ldt (j/local-date-time clock) + ldt+5 (j/+ ldt (j/days 5)) + ldt+10 (j/+ ldt (j/days 10))] + (is-< ldt ldt+5 ldt+10)) + + (let [ld (j/local-date clock) + ld+5 (j/+ ld (j/days 5)) + ld+10 (j/+ ld (j/days 10))] + (is-< ld ld+5 ld+10)) + + (let [lt (j/local-time clock) + lt+5 (j/+ lt (j/minutes 5)) + lt+10 (j/+ lt (j/minutes 10))] + (is-< lt lt+5 lt+10)) + + (let [zdt (j/zoned-date-time clock) + zdt+5 (j/+ zdt (j/minutes 5)) + zdt+10 (j/+ zdt (j/minutes 10))] + (is-< zdt zdt+5 zdt+10)) + + (let [odt (j/offset-date-time clock) + odt+5 (j/+ odt (j/minutes 5)) + odt+10 (j/+ odt (j/minutes 10))] + (is-< odt odt+5 odt+10)) + + (let [ot (j/offset-time clock) + ot+5 (j/+ ot (j/minutes 5)) + ot+10 (j/+ ot (j/minutes 10))] + (is-< ot ot+5 ot+10)) + + (let [i (j/instant clock) + i+5 (j/+ i (j/minutes 5)) + i+10 (j/+ i (j/minutes 10))] + (is-< i i+5 i+10))) + + (testing "clocks" + (let [fc (j/fixed-clock 0) + fc+1000 (j/fixed-clock 1000) + fc+2000 (j/fixed-clock 2000)] + (is-< fc fc+1000 fc+2000))) + + (testing "fields" + (let [thursday (j/day-of-week :thursday) + saturday (j/day-of-week :saturday) + sunday (j/day-of-week :sunday)] + (is-<-coerce thursday saturday sunday + :thursday :saturday :sunday) + (is-< thursday saturday sunday)) + + (let [january (j/month :january) + february (j/month :february) + march (j/month :march)] + (is-<-coerce january february march + :january :february :march) + (is-< january february march)) + + (let [year-2009 (j/year 2009) + year-2010 (j/year 2010) + year-2011 (j/year 2011)] + (is-<-coerce year-2009 year-2010 year-2011 + 2009 2010 2011) + (is-< year-2009 year-2010 year-2011)) + + (let [jan-1 (j/month-day 1 1) + apr-1 (j/month-day 4 1) + may-1 (j/month-day 5 1)] + (is-< jan-1 apr-1 may-1)))) + +(deftest mock-clock-test + (testing "constructors" + (is (= (j/mock-clock) + (j/mock-clock 0) + (j/mock-clock 0 (j/zone-id))))) + + (let [utc-clock #(j/mock-clock % "UTC")] + (testing "accessors" + (let [clock (utc-clock 0)] + (is (= 0 (j/value clock))) + (is (= (j/zone-id "UTC") (j/zone-id clock))))) + + (testing "equality" + (is (= (utc-clock 0) (utc-clock 0))) + (is (= (hash (utc-clock 0)) (hash (utc-clock 0)))) + (is (not= (utc-clock 0) (utc-clock 1))) + (is (not= (utc-clock 0) (j/mock-clock 0 "GMT")))) + + (testing "advance" + (let [clock (utc-clock 0)] + (testing "by positive amount" + (j/advance-clock! clock (j/millis 1)) + (is (= 1 (j/value clock)))) + + (testing "by negative amount" + (j/advance-clock! clock (j/millis -1)) + (is (= 0 (j/value clock)))))) + + (testing "clone with a different zone" + (let [clock (utc-clock 0) + cloned-clock (j/with-zone clock "GMT")] + (is (not (identical? clock cloned-clock))) + (is (= (j/zone-id "GMT") (j/zone-id cloned-clock))) + (is (= (j/value cloned-clock) (j/value clock))) + + (j/advance-clock! cloned-clock (j/seconds 1)) + (is (= 1000 (j/value cloned-clock))) + (is (not= (j/value cloned-clock) (j/value clock))))) + + (testing "set" + (let [clock (utc-clock 0)] + (testing "into future" + (j/set-clock! clock 100) + (is (= 100 (j/value clock)))) + + (testing "into past" + (j/set-clock! clock 0) + (is (= 0 (j/value clock)))))))) + +(deftest properties-test + (testing "units" + (is (= (j/unit :seconds) + (j/unit (j/duration) :seconds) + (j/unit (j/duration) (j/unit :seconds)))) + + (is (j/unit? (j/unit :seconds))) + (is (not (j/unit? nil))) + + (is (j/supports? (j/duration) :seconds)) + (is (j/supports? :seconds (j/local-date-time))) + (is (not (j/supports? :seconds (j/local-date)))) + + (is (= 60 + (j/time-between (j/local-time "15:40") (j/local-time "15:41") :seconds) + (j/time-between :seconds (j/local-time "15:40") (j/local-time "15:41")) + (j/time-between (j/unit :seconds) (j/local-time "15:40") (j/local-time "15:41"))))) + + (testing "fields" + (is (= (j/field :second-of-day) + (j/field (j/local-date-time) :second-of-day) + (j/field (j/local-date-time) (j/field :second-of-day)))) + + (is (j/field? (j/field :second-of-day))) + + (is (j/supports? (j/local-date-time) :second-of-day)) + (is (j/supports? :second-of-day (j/local-date-time))) + (is (j/supports? :rata-die (j/local-date-time))) + (is (not (j/supports? :second-of-day (j/local-date)))) + + (testing ", ranges" + (is (= (j/value-range 0 86399) + (j/range :second-of-day))) + + (is (= (j/value-range {:min-smallest 1, :min-largest 1, :max-smallest 28, :max-largest 31}) + (j/range :day-of-month) + (j/range (j/field :day-of-month)))) + + (is (= 1 (j/min-value :day-of-month))) + (is (= 1 (j/largest-min-value :day-of-month))) + (is (= 28 (j/smallest-max-value :day-of-month))) + (is (= 31 (j/max-value :day-of-month))))) + + (testing "duration" + (let [d (j/duration 100000001)] + (is (= (-> (j/properties d) + (update :nanos j/value) + (update :seconds j/value)) + {:nanos (j/value (j/property d :nanos)) + :seconds (j/value (j/property d :seconds))})) + (is (= (j/units d) + {:nanos (j/unit :nanos) + :seconds (j/unit :seconds)})))) + + (testing "period" + (let [p (j/period 10 5 1)] + (is (= (-> (j/properties p) + (update :days j/value) + (update :months j/value) + (update :years j/value)) + {:days (j/value (j/property p :days)) + :months (j/value (j/property p :months)) + :years (j/value (j/property p :years))})) + (is (= (j/units p) + {:days (j/unit :days) + :months (j/unit :months) + :years (j/unit :years)})))) + + (testing "temporals" + (doseq [e [(j/local-date) + (j/local-time) + (j/local-date-time) + (j/offset-date-time) + (j/offset-time) + (j/zoned-date-time)]] + (is (seq (j/properties e))) + (is (seq (j/fields e))))) + + (testing "single fields" + (doseq [e [(j/month :february) + (j/day-of-week :monday) + (j/year 100) + (j/zone-offset 5 20)]] + (is (seq (j/properties e))) + (is (seq (j/fields e))) + (is (j/range e)))) + + (testing "multi fields" + (doseq [e [(j/month-day :january 1) + (j/year-month 10 10)]] + (is (seq (j/properties e))) + (is (seq (j/fields e)))))) + +(deftest seq-test + (is (= [(j/local-date 2015) (j/local-date 2016)] + (take 2 (j/iterate j/+ (j/local-date 2015) (j/years 1)))))) + +(deftest adjuster-test + (testing "predefined adjusters" + (is (= (j/adjust (j/local-date 2015 1 1) :first-in-month :monday) + (j/local-date 2015 1 5))) + + (is (= (j/adjust (j/local-date 2015 1 1) :day-of-week-in-month 1 :monday) + (j/local-date 2015 1 5))) + + (is (= (j/adjust (j/local-date 2015 1 1) :day-of-week-in-month 2 :monday) + (j/local-date 2015 1 12))) + + (is (= (j/adjust (j/local-date 2015 1 1) :first-day-of-next-year) + (j/local-date 2016 1 1)))) + + (testing "functions as adjusters" + (is (= (j/adjust (j/local-date 2015 1 1) j/+ (j/days 1)) + (j/local-date 2015 1 2))))) + +(deftest sugar-test + (testing "weekdays" + (is (j/monday? (j/local-date 2015 1 5))) + (is (j/tuesday? (j/offset-date-time 2015 1 6 0))) + (is (j/wednesday? (j/zoned-date-time 2015 1 7))) + (is (j/thursday? (j/local-date-time 2015 1 8))) + (is (j/friday? (j/day-of-week 5))) + (is (j/saturday? (j/day-of-week :saturday))) + (is (j/sunday? (j/day-of-week 7)))) + + (testing "predicates" + (is (j/weekday? (j/local-date 2015 1 5))) + (is (not (j/weekday? (j/local-date 2015 1 4)))) + (is (j/weekend? (j/local-date 2015 1 4))) + (is (not (j/weekend? (j/local-date 2015 1 5)))))) + +(deftest convert-test + (testing "amount" + (is (= {:remainder 10, :whole 0} + (j/convert-amount 10 :seconds :minutes))) + (is (= {:remainder 323200, :whole 16} + (j/convert-amount 10000000 :seconds :weeks))) + (is (thrown? Exception + (j/convert-amount 10 :seconds :years))) + (is (thrown? Exception + (j/convert-amount 10 :years :forever)))) + + (testing "as" + (testing "duration" + (is (= 0 (j/as (j/duration 10 :seconds) :minutes))) + (is (= 10 (j/as (j/duration 10 :seconds) :seconds))) + (is (= 10000 (j/as (j/duration 10 :seconds) :millis))) + (is (thrown? Exception (j/as (j/duration 10 :seconds) :months)))) + + (testing "period" + (is (= 0 (j/as (j/days 1) :weeks))) + (is (= (* 24 60) (j/as (j/days 1) :minutes))) + (is (thrown? Exception (j/as (j/months 1) :minutes))) + (is (thrown? Exception (j/as (j/period 1 1 1) :months))) + (is (= 13 (j/as (j/period 1 1) :months)))) + + (testing "temporal" + (is (= 1 (j/as (j/local-date 2015 1 1) :day-of-month))) + (is (= 2015 (j/as (j/local-date 2015 1 1) :year)))) + + (testing "temporal-accessor" + (let [month-day-under-test (j/month-day 3 31)] + (is (= 3 (j/as month-day-under-test :month-of-year))) + (is (= 31 (j/as month-day-under-test :day-of-month))) + (is (thrown? Exception (j/as month-day-under-test :year)))) + (let [year-month-under-test (j/year-month 2018 3)] + (is (= 2018 (j/as year-month-under-test :year))) + (is (= 3 (j/as year-month-under-test :month-of-year))) + (is (thrown? Exception (j/as year-month-under-test :day-of-month)))) + (let [zoned-date-time-test (j/with-clock (j/system-clock "UTC") + (j/zoned-date-time 2018 3))] + (is (= 1519862400 (j/as zoned-date-time-test :instant-seconds))))) + + (testing "multiple" + (is (= [2015 1 1] (j/as (j/local-date 2015 1 1) :year :month-of-year :day-of-month)))) + + (testing "throws" + (is (thrown? Exception (j/as (j/local-time 0) :year)))))) + +(deftest legacy-conversion-test + (testing "deprecated" + (testing "converts through instant" + (is (= (j/instant 1000) (j/instant (java.util.Date. 1000)))) + (is (= (java.util.Date. 1000) (j/to-java-date 1000))) + (is (= (java.sql.Date/valueOf (j/local-date 1000)) (j/to-sql-date 1000))) + (is (= (java.sql.Timestamp/valueOf (j/local-date-time 1000)) (j/to-sql-timestamp 1000))) + (is (= 1000 + (j/to-millis-from-epoch 1000) + (j/to-millis-from-epoch (java.util.Date. 1000)) + (j/to-millis-from-epoch (j/offset-date-time (j/instant 1000) +0))))) + + (testing "converts to java.util/sql Dates" + (is (= (java.util.Date. 1000) (j/to-java-date (j/instant 1000)))) + (is (= (java.sql.Date/valueOf (j/local-date 2016)) (j/to-sql-date (j/local-date 2016)))))) + + (testing "pre-java8" + (is (= (j/java-date (j/instant 1000)) + (java.util.Date. 1000) + (j/java-date 1000))) + (is (= (java.sql.Date/valueOf (j/local-date 2000 10 5)) + (j/sql-date 2000 10 5) + (j/sql-date (j/local-date 2000 10 5)))) + (is (= (java.sql.Timestamp/valueOf (j/local-date-time 2000 10 5 20 30 40)) + (j/sql-timestamp 2000 10 5 20 30 40) + (j/sql-timestamp (j/local-date-time 2000 10 5 20 30 40)))) + (is (= (java.sql.Timestamp/from (j/instant 1)) + (java.sql.Timestamp. 1) + (j/instant->sql-timestamp (j/instant 1)) + (j/instant->sql-timestamp 1))) + (is (= (java.sql.Time/valueOf (j/local-time 20 30 40)) + (j/sql-time 20 30 40) + (j/sql-time (j/local-time 20 30 40)))) + + (is (= (j/local-date 2000 10 5) (j/local-date (j/sql-date 2000 10 5)))) + (is (= (j/local-date-time 2000 10 5 20 30 40 1000) + (j/local-date-time (j/sql-timestamp 2000 10 5 20 30 40 1000)))) + (is (= (j/instant 1) (j/instant (j/instant->sql-timestamp 1)))) + (is (= (j/local-time 20 30 40) (j/local-time (j/sql-time 20 30 40))))) + + (testing "from java.util Date types" + (is (= (j/zone-id "UTC") (j/zone-id (java.util.TimeZone/getTimeZone "UTC")))))) + +(jt.u/when-threeten-extra + (deftest threeten-extra-test + (testing "adjusters" + (is (= (j/adjust (j/local-date 2015 1 1) :next-working-day) + (j/local-date 2015 1 2)))) + + (testing "interval" + (is (= (j/interval "1970-01-01T00:00:00Z/1970-01-01T00:00:01Z") + (j/interval 0 1000) + (j/interval (j/offset-date-time 1970 1 1 0 0 0 0 +0) + (j/offset-date-time 1970 1 1 0 0 1 0 +0)))) + + (is (= 1 (j/as (j/interval (j/instant 0) (j/instant 1)) :millis))) + + (is (thrown-with-msg? IllegalArgumentException #"Cannot convert between.*" + (j/as (j/interval (j/instant 0) (j/instant 1)) :months)))) + + (testing "operations" + (is (= (j/interval 5000 10000) + (j/move-end-by (j/interval 5000 6000) (j/seconds 4)) + (j/move-start-by (j/interval 0 10000) (j/seconds 5)) + (j/move-end-to (j/interval 5000 6000) 10000) + (j/move-start-to (j/interval 0 10000) 5000))) + + (is (= (j/instant 0) (j/start (j/interval 0 1000)))) + (is (= (j/instant 1000) (j/end (j/interval 0 1000)))) + + (testing "contains" + (is (j/contains? (j/interval 0 1000) 0) + "inclusive start") + (is (j/contains? (j/interval 0 1000) 500)) + (is (not (j/contains? (j/interval 0 1000) 1000)) + "exclusive end") + (is (not (j/contains? (j/interval 0 1000) 1500))) + (is (j/contains? (j/interval 0 1000) (j/interval 100 900))) + (is (j/contains? (j/interval 0 1000) (j/interval 0 900))) + (is (j/contains? (j/interval 0 1000) (j/interval 0 1000))) + (is (j/contains? (j/interval 0 1000) (j/interval 1000 1000))) + (is (j/contains? (j/interval 1000 1000) (j/interval 1000 1000)) + "an empty interval encloses itself (via .encloses)") + (is (not (j/contains? (j/interval 0 1000) (j/interval 1000 1001))))) + + (testing "overlaps" + (is (j/overlaps? (j/interval 0 1000) (j/interval 0 500))) + (is (j/overlaps? (j/interval 0 1000) (j/interval 0 1500))) + (is (j/overlaps? (j/interval 500 1000) (j/interval 0 1500))) + (is (not (j/overlaps? (j/interval 0 1000) (j/interval 1500 2000)))) + + (is (= (j/interval 500 1000) (j/overlap (j/interval 500 1000) (j/interval 0 1500)))) + (is (nil? (j/overlap (j/interval 0 1000) (j/interval 1500 2000))))) + + (testing "abuts" + (is (j/abuts? (j/interval 0 1000) (j/interval 1000 2000))) + (is (not (j/abuts? (j/interval 0 1000) (j/interval 900 2000))))) + + (testing "gap" + (is (= (j/interval 1000 2000) (j/gap (j/interval 0 1000) (j/interval 2000 3000)))) + (is (nil? (j/gap (j/interval 0 1000) (j/interval 500 1500)))))) + + (testing "ordering" + (let [interval-1-2 (j/interval 1 2) + interval-3-4 (j/interval 3 4) + interval-1-3 (j/interval 1 3) + instant-1 (j/instant 1) + instant-2 (j/instant 2) + instant-3 (j/instant 3)] + (is-asymmetric (j/before? interval-1-2 interval-3-4)) + (is-asymmetric (j/before? interval-1-2 instant-3)) + (is-asymmetric ((complement j/before?) interval-3-4 instant-1)) + + (is-asymmetric (j/after? interval-3-4 interval-1-2)) + (is-asymmetric (j/after? interval-3-4 instant-1)) + (is-asymmetric ((complement j/after?) interval-1-2 instant-3)) + + (is-antisymmetric (j/<= interval-3-4 interval-3-4)) + (is (not (j/>= interval-1-2 interval-3-4))) + (is (not (j/>= interval-3-4 instant-3))) + (is (not (j/>= instant-3 interval-3-4))) + (is-antisymmetric (j/>= interval-3-4 instant-1)) + (is-antisymmetric ((complement j/>=) interval-1-2 instant-3)) + + (is-antisymmetric (j/<= interval-1-2 interval-1-2)) + (is-antisymmetric (j/<= interval-1-2 interval-3-4)) + (is (not (j/<= interval-1-2 instant-1))) + (is (not (j/<= instant-1 interval-1-2))) + (is (not (j/<= instant-1 interval-1-2 instant-2))) + (is (not (j/<= instant-1 interval-1-2 instant-2 interval-1-2 instant-1))) + (is (not (j/<= instant-1 interval-1-2 interval-1-2 instant-1))) + (is-antisymmetric (j/<= interval-1-2 instant-3)) + (is-antisymmetric ((complement j/<=) interval-3-4 instant-1))) + (testing "transitivity" + (let [interval-1-2 (j/interval 1 2) + interval-3-4 (j/interval 3 4) + interval-1-4 (j/interval 1 4) + interval-2-3 (j/interval 2 3) + interval-1-3 (j/interval 1 3) + instant-1 (j/instant 1) + instant-2 (j/instant 2) + instant-3 (j/instant 3)] + (is (not (j/<= instant-1 instant-2 instant-1))) + (is (not (j/<= instant-1 interval-1-3))) + (is (not (j/<= instant-1 interval-1-3))) + (is (not (j/<= instant-1 interval-1-3 instant-2 interval-1-3 instant-1))) + (is (not (j/< instant-1 interval-1-3 instant-2 interval-1-3 instant-1))) + (is (not (j/<= instant-2 interval-1-3 instant-1))) + (is (not (j/>= instant-1 interval-1-3 instant-2))) + (is (not (j/<= instant-1 interval-1-3 instant-2))) + (is (not (j/<= instant-1 interval-1-3))) + ;; instant-1 and interval-1-3 are unrelated, which does not work with + ;; implementations of <= based on negation + (is (not (j/after? instant-1 interval-1-3))) + (is (not (j/after? interval-1-3 instant-1))) + (is (not (j/before? instant-1 interval-1-3))) + (is (not (j/before? interval-1-3 instant-1))) + (is (not (= interval-1-3 instant-1))) + (is (not (j/<= interval-1-3 instant-1))) + (is (not (j/<= interval-1-3 instant-1))) + (is (not (j/<= instant-1 interval-1-3))) + (is (not (j/>= interval-1-3 instant-1))) + (is (not (j/>= instant-1 interval-1-3))) + (is (not (j/<= instant-1 interval-1-3 instant-3))) + (is (not (= interval-1-4 interval-2-3))) + (is (not (j/< interval-1-4 interval-2-3))) + (is (not (j/< interval-2-3 interval-1-4))) + (is (not (j/> interval-1-4 interval-2-3))) + (is (not (j/> interval-2-3 interval-1-4))) + (is (not (j/<= interval-1-4 interval-2-3))) + (is (not (j/<= interval-2-3 interval-1-4))) + (is (not (j/>= interval-1-4 interval-2-3))) + (is (not (j/>= interval-2-3 interval-1-4))))) + (is-asymmetric (j/before? (j/interval 1000 2000) (j/instant 5000))) + (testing "exclusive end" + (is-asymmetric (j/before? (j/interval 1000 5000) (j/instant 5000))) + (is-asymmetric (j/before? (j/interval 1000 5000) (j/interval 5000 6000)))) + (is-asymmetric (j/before? (j/interval 1000 5000) (j/interval 5001 6000))) + + (is-asymmetric (j/after? (j/interval 1000 5000) (j/instant 100))) + (is-asymmetric (j/after? (j/interval 1000 5000) (j/instant 999))) + (is (not (j/after? (j/interval 1000 5000) (j/instant 1000))) + "inclusive start") + (is (not (j/after? (j/instant 1000) (j/interval 1000 5000))) + "inclusive start") + (is (not (j/after? (j/interval 1000 5000) (j/instant 2000)))) + (is-asymmetric (j/after? (j/interval 1000 5000) (j/interval 100 999))) + (testing "exclusive end" + (is-asymmetric (j/after? (j/interval 1000 5000) (j/interval 100 1000)))) + (testing "instantinterval" + (is (not (j/after? (j/instant 100) (j/interval (j/instant 1000) (j/instant 2000)))) + "before start") + (is (not (j/after? (j/instant 1000) (j/interval (j/instant 1000) (j/instant 2000)))) + "at start") + (is (not (j/after? (j/instant 1500) (j/interval (j/instant 1000) (j/instant 2000)))) + "middle") + (is (not (j/after? (j/instant 1999) (j/interval (j/instant 1000) (j/instant 2000)))) + "before end") + (testing "end is exclusive" + (is-asymmetric (j/after? (j/instant 2000) (j/interval (j/instant 1000) (j/instant 2000))))) + (testing "after end" + (is-asymmetric (j/after? (j/instant 3000) (j/interval (j/instant 1000) (j/instant 2000))))))))) + +(jt.u/when-joda-time-loaded + + (def joda-clock (j/fixed-clock "2015-11-26T10:20:30.040Z" "UTC")) + + (import [org.joda.time Duration Period DateTimeZone + LocalDate LocalTime LocalDateTime DateTime Instant]) + (deftest joda-test + (testing "duration from duration and period" + (is (= (j/duration 1 :millis) + (j/duration (Duration/millis 1)) + (j/duration (Period/millis 1)))) + (is (= (j/duration 1 :seconds) + (j/duration (Duration/standardSeconds 1)) + (j/duration (Period/seconds 1)))) + (is (= (j/duration 1 :minutes) + (j/duration (Duration/standardMinutes 1)) + (j/duration (Period/minutes 1)))) + (is (= (j/duration 1 :hours) + (j/duration (Duration/standardHours 1)) + (j/duration (Period/hours 1)))) + (is (= (j/duration 1 :days) + (j/duration (Duration/standardDays 1)) + (j/duration (Period/days 1)))) + + (is (= (j/+ (j/millis 1) (j/seconds 1) (j/minutes 1) (j/hours 1) (j/standard-days 1)) + (j/duration (.plus (Duration/millis 1) + (.plus (Duration/standardSeconds 1) + (.plus (Duration/standardMinutes 1) + (.plus (Duration/standardHours 1) + (Duration/standardDays 1))))))))) + + (testing "duration from period" + (is (= (j/duration 7 :days) (j/duration (Period/weeks 1))))) + + (testing "period from duration" + (is (= (j/period 1 :days) (j/period (Duration/standardHours 24))))) + + (testing "period from joda period" + (is (= (j/period 1 :days) (j/period (Period/days 1)))) + (is (= (j/period 7 :days) (j/period (Period/weeks 1)))) + (is (= (j/period 1 :months) (j/period (Period/months 1)))) + (is (= (j/period 1 :years) (j/period (Period/years 1)))) + + (is (= (j/+ (j/days 1) (j/months 1) (j/years 1)) + (j/period (.plus (Period/days 1) + (.plus (Period/months 1) + (Period/years 1))))))) + + #_(testing "instant" + (is (= (j/instant joda-clock) + (j/instant (Instant. (DateTime. 2015 11 26 10 20 30)))))) + + (testing "local date" + (is (= (j/local-date joda-clock) + (j/local-date (LocalDate. 2015 11 26)) + (j/local-date (LocalDateTime. 2015 11 26 10 20 30)) + (j/local-date (DateTime. 2015 11 26 10 20 30))))) + + (testing "local date-time" + (is (= (j/local-date-time joda-clock) + (j/local-date-time (LocalDateTime. 2015 11 26 10 20 30 40)) + (j/local-date-time (DateTime. 2015 11 26 10 20 30 40))))) + + (testing "local time" + (is (= (j/local-time joda-clock) + (j/local-time (LocalTime. 10 20 30 40)) + (j/local-time (LocalDateTime. 2015 11 26 10 20 30 40)) + (j/local-time (DateTime. 2015 11 26 10 20 30 40))))) + + (testing "zoned date-time" + (is (= (j/zoned-date-time joda-clock) + (j/zoned-date-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))) + + (testing "offset date-time" + (is (= (j/offset-date-time joda-clock) + (j/offset-date-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))) + + (testing "offset time" + (is (= (j/offset-time joda-clock) + (j/offset-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))))) + +(deftest locale-test + (let [current-locale (Locale/getDefault) + test-langs ["en" "tr" "cn"]] + (testing "locale specific rules for lower-case can cause formatters to not be found" + (doseq [lang test-langs] + (testing lang + (try + (Locale/setDefault (Locale/forLanguageTag lang)) + (is (some? (j/formatter :rfc-1123-date-time))) + (finally + (Locale/setDefault current-locale)))))))) + +(deftest formatter-test + (testing "case-insensitive formatter" + (let [fmt (j/formatter "hh:mma" {:case :insensitive})] + (is (= (j/local-time 0 34 0 0) + (j/local-time fmt "00:34am") + (j/local-time fmt "00:34AM"))))) + + (testing "case-sensitive formatter" + (let [fmt (j/formatter "hh:mma" {:case :sensitive})] + (is (= (j/local-time 0 34 0 0) + (j/local-time fmt "12:34AM"))) + (is (thrown? Exception (j/local-time fmt "12:34am")))))) + +;; https://github.com/dm3/clojure.java-time/issues/75 +;; Q: Can we add a new function, or at least an example for converting a Unix timestamp (epoch seconds) to a LocalDateTime object? +(deftest unix-epoch-example-test + (is (= (j/local-date-time #inst "1970-01-01T00:00:00.100" "UTC") + (-> ;; A: First you must get an Instant as Unix epoch doesn't have time zone information. java-time/instant constructor accepts a number of milliseconds: + (j/instant 100) + ;; Then you'll get a LocalDateTime by providing the instant and the time zone to the local-date-time constructor: + (j/local-date-time "UTC"))))) + +;; https://github.com/dm3/clojure.java-time/issues/64 +(deftest instant-to-zoned-date-time-test + (is (= (j/zoned-date-time #inst "1970-01-01T00:00:00.100" "UTC") + (-> (j/instant 100) + (j/zoned-date-time "UTC"))))) diff --git a/test/java_time/dev/gen.clj b/test/java_time/dev/gen.clj new file mode 100644 index 0000000..4bd8807 --- /dev/null +++ b/test/java_time/dev/gen.clj @@ -0,0 +1,265 @@ +(ns java-time.dev.gen + (:require [clojure.string :as str] + [clojure.set :as set] + [clojure.walk :as walk]) + (:import (java.io Writer))) + +(def impl-local-sym '+impl+) + +(deftype DocString [value]) + +(defmethod print-method DocString + [^DocString this ^Writer w] + (->> (str/replace (.-value this) "\"" "\\\"") + (format "\"%s\"") + (.write w))) + +(defn normalize-argv [argv] + {:post [(or (empty? %) + (apply distinct? %)) + (not-any? #{impl-local-sym} %)]} + (into [] (map-indexed (fn [i arg] + (if (symbol? arg) + (do (assert (not (namespace arg))) + (if (some #(Character/isDigit (char %)) (name arg)) + (symbol (apply str (concat + (remove #(Character/isDigit (char %)) (name arg)) + [i]))) + arg)) + (symbol (str "arg" i))))) + argv)) + +(defn normalize-arities [arities] + (cond-> arities + (= 1 (count arities)) first)) + +(defn import-fn [sym] + {:pre [(namespace sym)]} + (let [vr (find-var sym) + m (meta vr) + n (:name m) + arglists (:arglists m) + protocol (:protocol m) + when-class (-> sym meta :when-class) + forward-meta (into (sorted-map) (select-keys m [:tag :arglists :doc :deprecated])) + _ (assert (not= n impl-local-sym)) + _ (when (:macro m) + (throw (IllegalArgumentException. + (str "Calling import-fn on a macro: " sym)))) + form (if protocol + (list* 'defn (with-meta n (dissoc forward-meta :arglists)) + (map (fn [argv] + {:pre [(not-any? #{'&} argv)]} + (list argv (list* sym argv))) + arglists)) + (list 'def (with-meta n forward-meta) sym))] + (cond->> form + when-class (list 'java-time.util/when-class when-class)))) + +(defn import-macro [sym] + (let [vr (find-var sym) + m (meta vr) + _ (when-not (:macro m) + (throw (IllegalArgumentException. + (str "Calling import-macro on a non-macro: " sym)))) + n (:name m) + arglists (:arglists m) + forwarded-meta (not-empty (into (sorted-map) (select-keys m [:doc :deprecated])))] + (list* 'defmacro (with-meta n forwarded-meta) + (concat + (normalize-arities + (map (fn [argv] + (let [argv (normalize-argv argv)] + (list argv + (if (some #{'&} argv) + (list* 'list* (list 'quote sym) (remove #{'&} argv)) + (list* 'list (list 'quote sym) argv))))) + arglists)))))) + +(defn import-vars + "Imports a list of vars from other namespaces." + [& syms] + (let [unravel (fn unravel [x] + (if (sequential? x) + (->> x + rest + (mapcat unravel) + (map + #(with-meta + (symbol + (str (first x) + (when-let [n (namespace %)] + (str "." n))) + (name %)) + (meta %)))) + [x])) + syms (mapcat unravel syms)] + (map (fn [sym] + (let [vr (if-some [rr (resolve 'clojure.core/requiring-resolve)] + (rr sym) + (do (require (-> sym namespace symbol)) + (resolve sym))) + _ (assert vr (str sym " is unresolvable")) + m (meta vr)] + (if (:macro m) + (import-macro sym) + (import-fn sym)))) + syms))) + +(def impl-info + {:macros '[[java-time.clock with-clock] + [java-time.util when-joda-time-loaded]] + :threeten-extra-fns ['[java-time.interval interval interval?] + + '[java-time.single-field + am-pm am-pm? quarter quarter? day-of-month day-of-month? + day-of-year day-of-year? year-quarter year-quarter?]] + :fns ['[java-time.clock with-clock-fn] + '[java-time.core + zero? negative? negate abs max min + before? not-after? after? not-before? + supports? + fields units properties property + as value range min-value max-value largest-min-value smallest-max-value + truncate-to time-between with-zone + plus minus multiply-by + < > <= >= * - + = + ;; TODO below here needs unit tests + chronology leap? with-value with-min-value with-max-value with-largest-min-value with-smallest-max-value] + + '[java-time.amount + duration period period? duration? + nanos micros millis seconds minutes hours standard-days + days weeks months years] + + '[java-time.properties + unit? unit field? field] + + '[java-time.temporal + value-range instant instant?] + + '[java-time.local + local-date local-date-time local-time + local-date? local-date-time? local-time?] + + '[java-time.single-field + year year? month month? day-of-week day-of-week? month-day month-day? + year-month year-month?] + + '[java-time.zone + available-zone-ids zone-id zone-offset + offset-date-time offset-time zoned-date-time + system-clock fixed-clock offset-clock tick-clock clock? + zone-id? zoned-date-time? offset-date-time? offset-time? + with-zone-same-instant with-offset with-offset-same-instant] + + '[java-time.mock mock-clock advance-clock! set-clock!] + + '[java-time.convert + as-map convert-amount to-java-date to-sql-date to-sql-timestamp + to-millis-from-epoch] + + '[java-time.sugar + monday? tuesday? wednesday? thursday? friday? saturday? sunday? + weekend? weekday?] + + '[java-time.seqs iterate] + + '[java-time.adjuster adjust] + + '[java-time.format format formatter] + + '[java-time.pre-java8 java-date sql-date sql-timestamp instant->sql-timestamp + ^{:when-class "java.sql.Time"} sql-time] + + '[java-time.interval + move-start-to move-end-to move-start-by move-end-by + start end contains? overlaps? abuts? overlap gap]]}) + +(defn gen-java-time-ns-forms [nsym] + (let [require-macros (into #{} (map first) (:macros impl-info)) + require-fns #_(set/difference (into #{} (map first) + (concat (:threeten-extra-fns impl-info) + (:fns impl-info))) + require-macros) + ;;FIXME implementations must be loaded in this order for a stable graph traversal (I think) + (into #{} (map #(symbol (str "java-time." %))) + '[core properties temporal amount zone single-field local chrono + convert sugar seqs adjuster interval format joda clock pre-java8 mock])] + (concat + [";; NOTE: This namespace is generated by java-time.dev.gen" + `(~'ns ~nsym + (:refer-clojure :exclude ~'(zero? range iterate max min contains? format abs + < > <= >= = * - + neg?)) + (:require ~'[java-time core properties temporal amount zone single-field local chrono + convert sugar seqs adjuster interval format joda clock pre-java8 mock]))] + (apply import-vars (:macros impl-info)) + (apply import-vars (:fns impl-info)) + + [(list* 'java-time.util/when-class "org.threeten.extra.Temporals" (apply import-vars (:threeten-extra-fns impl-info)))]))) + +(defn print-form [form] + (with-bindings + (cond-> {#'*print-meta* true + #'*print-length* nil + #'*print-level* nil} + (resolve '*print-namespace-maps*) + (assoc (resolve '*print-namespace-maps*) false)) + (cond + (string? form) (println form) + :else (println (pr-str (walk/postwalk + (fn [v] + (if (meta v) + (if (symbol? v) + (vary-meta v #(not-empty + (cond-> (sorted-map) + (some? (:tag %)) (assoc :tag (:tag %)) + (some? (:doc %)) (assoc :doc (DocString. (:doc %))) + ((some-fn true? string?) (:deprecated %)) (assoc :deprecated (:deprecated %)) + (string? (:superseded-by %)) (assoc :superseded-by (:superseded-by %)) + (string? (:supercedes %)) (assoc :supercedes (:supercedes %)) + (some? (:arglists %)) (assoc :arglists (list 'quote (doall (map normalize-argv (:arglists %)))))))) + (with-meta v nil)) + v)) + form))))) + nil) + +(defn print-java-time-ns [nsym] + (run! print-form (gen-java-time-ns-forms nsym))) + +(def java-time-nsym + (with-meta + 'java-time + {:superseded-by "java-time.api" + :deprecated "1.1.0" + :doc + "This namespace has been deprecated due to [#91](https://github.com/dm3/clojure.java-time/issues/91). + Please migrate to [[java-time.api]] + + This namespace will continue to exist and be updated. For + maximum JVM compatibility, please migrate to `java-time.api`, + which provides the same interface. `java-time` and `java-time.api` + and can be freely intermixed within the same library, so you can + safely migrate your own code even if your dependencies use the old namespace. + + Migration steps: + + 1. rename all references from `java-time` to [[java-time.api]]. + eg., `(:require [java-time :as jt])` => `(:require [java-time.api :as jt])`"})) +(def java-time-api-nsym + (with-meta + 'java-time.api + {:supercedes "java-time"})) + +(def gen-source->nsym + {"src/java_time.clj" java-time-nsym + "src/java_time/api.clj" java-time-api-nsym}) + +(defn spit-java-time-ns [] + (doseq [[source nsym] gen-source->nsym] + (spit source (with-out-str (print-java-time-ns nsym))))) + +(comment + (print-java-time-ns java-time-nsym) + (spit-java-time-ns) + ) diff --git a/test/java_time/dev/gen_test.clj b/test/java_time/dev/gen_test.clj new file mode 100644 index 0000000..c89f811 --- /dev/null +++ b/test/java_time/dev/gen_test.clj @@ -0,0 +1,15 @@ +(ns java-time.dev.gen-test + (:require [clojure.test :refer [deftest is]] + [java-time.util :as jt.u])) + +(jt.u/when-threeten-extra + (require 'java-time.dev.gen) + (deftest gen-test + (doseq [[source nsym] (doto @(resolve 'java-time.dev.gen/gen-source->nsym) + (-> not-empty assert))] + (let [actual (slurp source) + expected (with-out-str ((resolve 'java-time.dev.gen/print-java-time-ns) + nsym)) + up-to-date? (= actual expected)] + (is up-to-date? + "Please run `lein doc` and commit the changes"))))) diff --git a/test/java_time/test_utils.clj b/test/java_time/test_utils.clj new file mode 100644 index 0000000..019f726 --- /dev/null +++ b/test/java_time/test_utils.clj @@ -0,0 +1,241 @@ +(ns java-time.test-utils + (:refer-clojure :exclude [boolean?]) + (:require [clojure.math.combinatorics :as comb] + [clojure.test :refer [deftest is]])) + +(def boolean? #(or (true? %) (false? %))) + +(defn ^:private validate-_is-args [msg] + (assert (string? msg) (str "is: message must be a string: " (pr-str msg)))) + +(defn ^:dynamic _is [f args msg] + (validate-_is-args msg) + (is (apply f args) msg)) + +(defn ^:private reorder-vector [v order] + (assert ((every-pred vector?) v order)) + (assert (= (count v) (count order))) + (assert (next order)) + (assert (apply distinct? order)) + (reduce (fn [v' [from to]] + (assoc v' to (nth v from))) + v (map vector (range (count v)) order))) + +(deftest ^:private reorder-vector-test + (is (= '[a b c d] + (reorder-vector '[a b c d] [0 1 2 3]))) + (is (= '[a b d c] + (reorder-vector '[a b c d] [0 1 3 2]))) + (is (= '[d c b a] + (reorder-vector '[a b c d] [3 2 1 0])))) + +; aRb => !bRa +; aRb && bRc => !bRa && !cRb && !cRa && aRc +(defn is-asymmetric* [prop R args R-syn args-syn] + {:pre [((every-pred vector?) args args-syn) + (#{:asymmetric :antisymmetric} prop)] + :post [(boolean? %)]} + (let [nargs (count args) + _ (assert (= nargs (count args-syn))) + _ (assert (<= 2 nargs) "Must provide at least 2 arguments") + split-args+syn (fn [args+syn] + [(mapv first args+syn) + (mapv second args+syn)]) + args+syn (mapv vector args args-syn) + continue (volatile! true) + _ (doseq [;; for each combination of 2 or more args + nargs (range 2 (inc nargs)) + :while @continue + args+syn (map vec (comb/combinations args+syn nargs)) + :let [[args args-syn] (split-args+syn args+syn)] + ;; (R args...) is true + :while (or (_is R args (pr-str (list* R-syn args-syn))) + (vreset! continue false)) + :let [original-order (range nargs)] + order (comb/permutations original-order) + :while @continue + :when (not= order original-order) + :let [[args args-syn] (split-args+syn (reorder-vector args+syn order))] + :while (or (case prop + ;; and (R args..) is false for every *other* permutation of args + :asymmetric (_is (complement R) args (pr-str (list 'not (list* R-syn args-syn)))) + ;; and (R args..) is false for every *other* permutation of args, or one of the + ;; out-of-order arguments is equal + :antisymmetric (let [out-of-order-args (loop [out [] + order order] + (if (next order) + (let [[l r] order] + (recur (cond-> out + (> l r) (conj [l r])) + (next order))) + out)) + _ (assert (seq out-of-order-args)) + f (fn [& args] + (let [args (vec args)] + (if (apply R args) + (every? (fn [[l r]] + (= (nth args l) + (nth args r))) + out-of-order-args) + true))) + conjunction-syn (mapv (fn [[l r]] + (list '= (nth args-syn l) (nth args-syn r))) + out-of-order-args)] + (_is f args (pr-str (list 'or (list 'not (list* R-syn args-syn)) + (if (= 1 (count conjunction-syn)) + (first conjunction-syn) + (list* 'and conjunction-syn))))))) + (vreset! continue false))])] + @continue)) + +(defmacro is-asymmetric + "With two arguments, tests that (R a b) is true and (R b a) is false. + With three arguments (R a b c): + 1. tests the previous property for (R a b), (R b c), and (R a c) + 2. tests that (R a b c) is true. + 3. tests that these are false: (R a c b), (R b a c), (R b c a), (R c a b), (R c b a). + + Similar for four or more arguments." + [[R a b & args :as all]] + (assert (seq? all)) + (assert (<= 3 (count all)) + (str "Must provide 2 or more arguments: " (pr-str all))) + `(is-asymmetric* :asymmetric + ~R (into [~a ~b] ~(vec args)) + '~R (into '~[a b] '~(vec args)))) + +; aRb && bRa => a=b +(defmacro is-antisymmetric + "With two arguments (R a b), tests that: + 1. (R a b) is true + 2. if (R b a) then a=b + With three arguments (R a b c): + 1. tests the previous property for (R a b), (R b c), and (R a c) + 2. tests that (R a b c) is true. + 3. tests that + - if (R a c b) then b=c + - if (R b a c) then a=b + - if (R b c a) then c=a + - if (R c a b) then c=a + - if (R c b a) then a=b and b=c + + Similar for four or more arguments." + [[R a b & args :as all]] + (assert (seq? all)) + (assert (<= 3 (count all)) + (str "Must provide 2 or more arguments: " (pr-str all))) + `(is-asymmetric* :antisymmetric + ~R (into [~a ~b] ~(vec args)) + '~R (into '~[a b] '~(vec args)))) + +(defn ^:private with-expected-results* + [expected-results f] + (assert (even? (count expected-results))) + (let [actual-results (atom []) + _ (binding [_is (fn [f args msg] + (validate-_is-args msg) + (let [res (apply f args)] + (swap! actual-results conj (read-string msg) (if res :pass :fail)) + res))] + (f)) + actual-results @actual-results] + (or (= expected-results actual-results) + (throw (ex-info (str "Expected result: " + (pr-str expected-results) + "\n Actual result: " + (pr-str actual-results)) + {:expected-result expected-results + :actual-results actual-results}))))) + +(defmacro ^:private with-expected-results + [results & body] + `(with-expected-results* '~results #(do ~@body))) + +(defn ^:private is-ex-data* [expected-ex-data f] + (try (f) + (is false (str "No error thrown")) + (catch Exception e + (is (= expected-ex-data (ex-data e)))))) + +(defmacro ^:private is-ex-data [expected-ex-data body] + `(is-ex-data* ~expected-ex-data #(do ~body))) + +(deftest ^:private _is-test + (is (with-expected-results [(< 2 1) :pass] + (_is (constantly true) [] "(< 2 1)"))) + (is-ex-data + '{:expected-result [(< 2 1) :fail] + :actual-results [(< 2 1) :pass]} + (with-expected-results [(< 2 1) :fail] + (_is (constantly true) [] "(< 2 1)"))) + (is-ex-data + '{:expected-result [(< 2 1) :pass] + :actual-results [(< 2 1) :pass + (< 2 1) :pass]} + (with-expected-results [(< 2 1) :pass] + (_is (constantly true) [] "(< 2 1)") + (_is (constantly true) [] "(< 2 1)")))) + +(deftest ^:private is-asymmetric-test + (is (with-expected-results [(< 1 2) :pass + (not (< 2 1)) :pass] + (is-asymmetric (< 1 2)))) + (let [a 1 + b 2] + (is (with-expected-results [(< a b) :pass + (not (< b a)) :pass] + (is-asymmetric (< a b))))) + (is (with-expected-results [(> 1 2) :fail] + (is-asymmetric (> 1 2)))) + (is (with-expected-results [(<= 1 1) :pass + (not (<= 1 1)) :fail] + (is-asymmetric (<= 1 1)))) + (is (with-expected-results [(<= 1 1) :pass + (not (<= 1 1)) :fail] + (is-asymmetric (<= 1 1 1 1 1 1)))) + (is (with-expected-results + [(< 1 2) :pass + (not (< 2 1)) :pass + (< 1 3) :pass + (not (< 3 1)) :pass + (< 2 3) :pass + (not (< 3 2)) :pass + (< 1 2 3) :pass + (not (< 1 3 2)) :pass + (not (< 2 1 3)) :pass + (not (< 3 1 2)) :pass + (not (< 2 3 1)) :pass + (not (< 3 2 1)) :pass] + (is-asymmetric (< 1 2 3))))) + +(deftest ^:private is-antisymmetric-test + (is (with-expected-results [(<= 1 1) :pass + (or (not (<= 1 1)) (= 1 1)) :pass] + (is-antisymmetric (<= 1 1)))) + (let [a 1 + b 1] + (is (with-expected-results [(<= a b) :pass + (or (not (<= b a)) (= a b)) :pass] + (is-antisymmetric (<= a b))))) + (is (with-expected-results [(<= 1 2) :pass + (or (not (<= 2 1)) (= 1 2)) :pass] + (is-antisymmetric (<= 1 2)))) + (is (with-expected-results [(> 1 2) :fail] + (is-antisymmetric (> 1 2)))) + (is (with-expected-results [(> 2 1) :pass + (or (not (> 1 2)) (= 2 1)) :pass] + (is-antisymmetric (> 2 1)))) + (is (with-expected-results + [(<= 1 2) :pass + (or (not (<= 2 1)) (= 1 2)) :pass + (<= 1 3) :pass + (or (not (<= 3 1)) (= 1 3)) :pass + (<= 2 3) :pass + (or (not (<= 3 2)) (= 2 3)) :pass + (<= 1 2 3) :pass + (or (not (<= 1 3 2)) (= 2 3)) :pass + (or (not (<= 2 1 3)) (= 1 2)) :pass + (or (not (<= 3 1 2)) (= 2 3)) :pass + (or (not (<= 2 3 1)) (= 1 2)) :pass + (or (not (<= 3 2 1)) (and (= 1 2) (= 2 3))) :pass] + (is-antisymmetric (<= 1 2 3))))) diff --git a/test/java_time_test.clj b/test/java_time_test.clj index 4ae7f89..0907717 100644 --- a/test/java_time_test.clj +++ b/test/java_time_test.clj @@ -1,1034 +1,25 @@ (ns java-time-test - (:require [clojure.test :refer :all] - [java-time.util :as jt.u] - [java-time :as j]) - (:import java.util.Locale)) - -(def clock (j/fixed-clock "2015-11-26T10:20:30.000000040Z" "UTC")) - -(deftest constructors - (testing "clocks" - (testing ", with-clock" - (are [f] (= (j/with-clock clock (f)) (f clock)) - j/zoned-date-time - j/offset-date-time - j/offset-time - j/local-date-time - j/local-time - j/local-date - j/zone-offset - j/zone-id)) - - (testing ", system" - (let [now-millis (j/value (j/system-clock))] - (is (<= now-millis - (j/value (j/system-clock "UTC")))) - (is (= (j/system-clock "UTC") - (j/with-zone (j/system-clock "Europe/Zurich") "UTC"))))) - - (testing ", fixed" - (is (= (j/value (j/fixed-clock "2015-01-01T10:20:30Z" "UTC")) - (j/value (j/fixed-clock "2015-01-01T10:20:30Z"))))) - - (testing ", offset" - (is (= (str (-> (j/fixed-clock "2015-01-01T10:20:30Z" "UTC") - (j/offset-clock (j/minutes 30)))) - "OffsetClock[FixedClock[2015-01-01T10:20:30Z,UTC],PT30M]"))) - - (testing ", tick" - (is (= (str (-> (j/fixed-clock "2015-01-01T10:20:30Z" "UTC") - (j/tick-clock (j/minutes 10)))) - "TickClock[FixedClock[2015-01-01T10:20:30Z,UTC],PT10M]")))) - - (testing "offsets" - (is (= (j/zone-offset +0) - (j/zone-offset "+00:00") - (j/zone-offset -0) - (j/zone-offset 0 0))) - - (is (= (j/zone-offset 1 30) - (j/zone-offset "+01:30") - (j/zone-offset 1 30 0) - (j/zone-offset +1.5)))) - - (testing "enums" - (is (= (j/month 11) - (j/month :november) - (j/month (j/local-date clock)) - (j/month "MM" "11"))) - - (is (j/month? (j/month 7))) - - (is (= (j/day-of-week 4) - (j/day-of-week :thursday) - (j/day-of-week (j/local-date clock)))) - - (is (j/day-of-week? (j/day-of-week 4)))) - - (testing "multi field" - (is (= (j/month-day (j/local-date clock)) - (j/month-day 11 26) - (j/month-day "dd-MM" "26-11"))) - - (is (= (j/month-day 1) - (j/month-day (j/month 1)) - (j/month-day 1 1) - (j/month-day 1 (j/day-of-week 1)))) - - (is (j/month-day? (j/month-day 1 1))) - - (is (= (j/year-month (j/local-date clock)) - (j/year-month 2015 11) - (j/year-month "yy-MM" "15-11"))) - - (is (= (j/year-month 1) - (j/year-month (j/year 1)) - (j/year-month 1 1) - (j/year-month 1 (j/month 1)))) - - (is (j/year-month? (j/year-month 1 1)))) - - (testing "years" - (is (= (j/year clock) - (j/year "2015") - (j/year 2015) - (j/year "yy" "15"))) - - (is (= (j/year "UTC") - (j/year (j/zone-id "UTC")))) - - (is (j/year? (j/year 2015)))) - - (testing "local date" - (is (= (j/local-date clock) - (j/local-date 2015 11 26) - (j/local-date "2015-11-26") - (j/local-date "yyyy/MM/dd" "2015/11/26") - (j/local-date (j/local-date 2015 11 26)) - (j/local-date (j/local-date-time clock)) - (j/local-date (j/zoned-date-time clock)) - (j/local-date (j/offset-date-time clock)) - (j/local-date (j/instant clock) "UTC") - (j/local-date (j/to-java-date clock) "UTC"))) - - (is (j/local-date? (j/local-date))) - - (is (= (j/local-date 2015) - (j/local-date 2015 1) - (j/local-date 2015 1 1) - (j/local-date (j/year 2015) (j/month 1)) - (j/local-date (j/year 2015) (j/month 1) (j/day-of-week 1))))) - - (testing "local time" - (is (= (j/local-time clock) - (j/local-time 10 20 30 40) - (j/local-time "10:20:30.000000040") - (j/local-time "HH:mm,ss:SSSSSSSSS" "10:20,30:000000040") - (j/local-time (j/local-time clock)) - (j/local-time (j/local-date-time clock)) - (j/local-time (j/zoned-date-time clock)) - (j/local-time (j/offset-date-time clock)) - (j/local-time (j/instant clock) "UTC"))) - - (is (= (j/truncate-to (j/local-time clock) :millis) - (j/local-time (j/to-java-date clock) "UTC"))) - - (is (j/local-time? (j/local-time))) - - (is (= (j/local-time 10) - (j/local-time 10 0) - (j/local-time 10 0 0) - (j/local-time 10 0 0 0))) - - (is (= (j/truncate-to (j/local-time 10 20 30 40) :minutes) - (j/local-time 10 20)))) - - (testing "local date time" - (is (= (j/local-date-time clock) - (j/local-date-time 2015 11 26 10 20 30 40) - (j/local-date-time "2015-11-26T10:20:30.000000040") - (j/local-date-time "yyyy/MM/dd'T'SSSSSSSSS,HH:mm:ss" "2015/11/26T000000040,10:20:30") - (j/local-date-time (j/local-date 2015 11 26) (j/local-time 10 20 30 40)) - (j/local-date-time (j/local-date-time clock)) - (j/local-date-time (j/zoned-date-time clock)) - (j/local-date-time (j/offset-date-time clock)) - (j/local-date-time (j/instant clock) "UTC"))) - - (is (= (j/truncate-to (j/local-date-time clock) :millis) - (j/local-date-time (j/to-java-date clock) "UTC"))) - - (is (j/local-date-time? (j/local-date-time))) - - (is (= (j/local-date-time 2015) - (j/local-date-time 2015 1) - (j/local-date-time 2015 1 1) - (j/local-date-time (j/year 2015) (j/month 1)) - (j/local-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) - (j/local-date-time 2015 1 1 0) - (j/local-date-time 2015 1 1 0 0) - (j/local-date-time 2015 1 1 0 0 0) - (j/local-date-time 2015 1 1 0 0 0 0))) - - (is (= (j/truncate-to (j/local-date-time 2015 1 1 10 20 30 40) :minutes) - (j/local-date-time 2015 1 1 10 20)))) - - (testing "zoned date time" - (is (= (j/zoned-date-time clock) - (j/zoned-date-time (j/zoned-date-time clock)) - (j/zoned-date-time "2015-11-26T10:20:30.000000040+00:00[UTC]") - (j/zoned-date-time "2015-11-26T10:20:30.000000040Z[UTC]") - (j/zoned-date-time "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['VV']'" "2015/11/26T10:20:30-000000040[UTC]") - (j/zoned-date-time (j/local-date clock) (j/local-time clock) "UTC") - (j/zoned-date-time (j/local-date-time clock) "UTC") - (j/zoned-date-time (j/offset-date-time clock) "UTC") - (j/zoned-date-time 2015 11 26 10 20 30 40 "UTC") - (j/zoned-date-time (j/instant clock) "UTC"))) - - (is (= (j/truncate-to (j/zoned-date-time clock) :millis) - (j/zoned-date-time (j/to-java-date clock) "UTC"))) - - (is (j/zoned-date-time? (j/zoned-date-time (j/zone-id "UTC")))) - - (j/with-clock (j/system-clock "UTC") - (is (= (j/zoned-date-time 2015) - (j/zoned-date-time 2015 1) - (j/zoned-date-time 2015 1 1) - (j/zoned-date-time (j/year 2015)) - (j/zoned-date-time (j/year 2015) (j/month 1)) - (j/zoned-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) - (j/zoned-date-time 2015 1 1 0) - (j/zoned-date-time 2015 1 1 0 0) - (j/zoned-date-time 2015 1 1 0 0 0) - (j/zoned-date-time 2015 1 1 0 0 0 0)))) - - (let [zone-id (j/zone-id)] - (is (= (j/zoned-date-time 2015 1 1 0 0 0 0) - (j/zoned-date-time 2015 1 1 0 0 0 0 zone-id)))) - - (let [utc (j/zoned-date-time 2015 1 1 0 0 0 0 "UTC")] - (is (= (j/zoned-date-time 2014 12 31 19 0 0 0 "America/New_York") - (j/with-zone-same-instant utc "America/New_York") - (j/with-zone (j/zoned-date-time 2014 12 31 19 0 0 0 "UTC") "America/New_York")))) - - (is (= (j/truncate-to (j/zoned-date-time 2015 1 1 10 20 30 40) :minutes) - (j/zoned-date-time 2015 1 1 10 20)))) - - (testing "offset date time" - (is (= (j/offset-date-time clock) - (j/offset-date-time (j/offset-date-time clock)) - (j/offset-date-time "2015-11-26T10:20:30.000000040+00:00") - (j/offset-date-time "2015-11-26T10:20:30.000000040Z") - (j/offset-date-time "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['X']'" "2015/11/26T10:20:30-000000040[Z]") - (j/offset-date-time (j/local-date clock) (j/local-time clock) (j/zone-offset +0)) - (j/offset-date-time (j/local-date-time clock) (j/zone-offset +0)) - (j/offset-date-time (j/zoned-date-time clock) (j/zone-offset +0)) - (j/offset-date-time 2015 11 26 10 20 30 40 (j/zone-offset +0)) - (j/offset-date-time (j/instant clock) "UTC"))) - - (is (= (j/truncate-to (j/offset-date-time clock) :millis) - (j/offset-date-time (j/to-java-date clock) "UTC"))) - - (is (j/offset-date-time? (j/offset-date-time))) - - (j/with-clock (j/system-clock "UTC") - (is (= (j/offset-date-time 2015) - (j/offset-date-time 2015 1) - (j/offset-date-time 2015 1 1) - (j/offset-date-time (j/year 2015)) - (j/offset-date-time (j/year 2015) (j/month 1)) - (j/offset-date-time (j/year 2015) (j/month 1) (j/day-of-week 1)) - (j/offset-date-time 2015 1 1 0) - (j/offset-date-time 2015 1 1 0 0) - (j/offset-date-time 2015 1 1 0 0 0) - (j/offset-date-time 2015 1 1 0 0 0 0 (j/zone-offset +0))))) - - (is (= (j/truncate-to (j/offset-date-time 2015 1 1 10 20 30 40) :minutes) - (j/offset-date-time 2015 1 1 10 20))) - - (let [utc (j/offset-date-time 2015 1 1 0 0 0 0 +0)] - (is (= (j/offset-date-time 2014 12 31 19 0 0 0 -5) - (j/with-offset-same-instant utc -5) - (j/with-offset (j/offset-date-time 2014 12 31 19 0 0 0 +0) -5))))) - - (testing "offset time" - (is (= (j/offset-time clock) - (j/offset-time (j/offset-time clock)) - (j/offset-time (j/zoned-date-time clock)) - (j/offset-time "10:20:30.000000040+00:00") - (j/offset-time "10:20:30.000000040Z") - (j/offset-time "HH:mm:ss-SSSSSSSSS'['X']'" "10:20:30-000000040[Z]") - (j/offset-time (j/local-time clock) (j/zone-offset +0)) - (j/offset-time (j/instant clock) "UTC") - (j/offset-time 10 20 30 40 +0) - (j/offset-time (j/instant clock) "UTC"))) - - (is (= (j/truncate-to (j/offset-time clock) :millis) - (j/offset-time (j/to-java-date clock) "UTC"))) - - (is (j/offset-time? (j/offset-time (j/zone-id "UTC")))) - (is (j/offset-time? (j/offset-time +0))) - - (j/with-clock (j/system-clock "UTC") - (is (= (j/offset-time 0) - (j/offset-time 0 0) - (j/offset-time 0 0 0) - (j/offset-time 0 0 0 0)))) - - (is (= (j/truncate-to (j/offset-time 10 20 30 40) :minutes) - (j/offset-time 10 20))) - - (let [utc (j/offset-time 15 0 0 0 +0)] - (is (= (j/offset-time 10 0 0 0 -5) - (j/with-offset-same-instant utc -5) - (j/with-offset (j/offset-time 10 0 0 0 +0) -5))))) - - (testing "instant" - (is (= (j/instant clock) - (j/instant "2015-11-26T10:20:30.000000040Z") - (j/instant "yyyy/MM/dd'T'HH:mm:ss-SSSSSSSSS'['X']'" "2015/11/26T10:20:30-000000040[Z]"))) - - (is (= (j/truncate-to (j/instant clock) :millis) - ;; (.toEpochMilli instant) - (j/instant 1448533230000)))) - - (testing "duration" - (is (= (j/duration 100) - (j/duration (j/duration 100)) - (j/duration "PT0.1S") - (j/duration (j/local-time 0 0 0 0) (j/local-time 0 0 0 (* 100 1000 1000))) - (j/duration 100 :millis))) - - (is (j/duration? (j/duration)))) - - (testing "period" - (is (= (j/period 10 20 30) - (j/period "P10Y20M30D"))) - - (is (= (j/period 11 9) - (j/period (j/local-date 2001 1 1) (j/local-date 2012 10 1)))) - - (is (= (j/period) - (j/period 0) - (j/period 0 0) - (j/period 0 0 0) - (j/period 0 :years) - (j/period 0 :months) - (j/period 0 :days))) - - (is (j/period? (j/period))))) - -(deftest operations - (testing "duration" - (testing "plus" - (is (= (j/duration 100000001) - (j/plus (j/standard-days 1) (j/hours 3) (j/minutes 46) (j/seconds 40) (j/millis 1) (j/nanos 0)) - (j/plus (j/duration 1 :days) - (j/duration 3 :hours) - (j/duration 46 :minutes) - (j/duration 40 :seconds) - (j/duration 1 :millis) - (j/duration 0 :nanos))))) - - (testing "minus" - (is (= (j/duration "PT22H58M58.998999999S") - (j/minus (j/standard-days 1) (j/hours 1) (j/minutes 1) (j/seconds 1) (j/millis 1) (j/nanos 1))))) - - (testing "multiply" - (is (= (j/hours 2) - (j/multiply-by (j/hours 1) 2)))) - - (testing "number ops" - (is (j/zero? (j/duration 0))) - (is (= (j/duration 10) (j/abs (j/duration -10)))) - (is (= (j/duration -10) (j/negate (j/duration 10)))) - (is (j/negative? (j/duration -10))))) - - (testing "period" - (testing "plus" - (is (= (j/period 10 20 30) - (j/plus (j/years 10) (j/months 20) (j/days 30)) - (j/plus (j/period 10) - (j/period 0 20) - (j/period 0 0 30)) - (j/plus (j/period 10 :years) - (j/period 20 :months) - (j/period 30 :days))))) - - (testing "minus" - (is (= (j/period 0 0 0) - (j/minus (j/period 10 20 30) - (j/years 10) (j/months 20) (j/days 30))))) - - (testing "multiply" - (is (= (j/days 2) - (j/multiply-by (j/days 1) 2)))) - - (testing "number ops" - (is (j/zero? (j/period 0))) - (is (= (j/period -10 10) (j/negate (j/period 10 -10)))) - (is (j/negative? (j/period -10))) - (is (j/negative? (j/period -10 10))))) - - (testing "year" - (testing "plus" - (is (= (j/year 5) - (j/plus (j/year 2) (j/years 3))))) - - (testing "minus" - (is (= (j/year 0) - (j/minus (j/year 5) (j/years 5)))))) - - (testing "month" - (testing "plus" - (is (= (j/month :may) - (j/plus (j/month 2) 3) - (j/plus (j/month 2) (j/months 3))))) - - (testing "minus" - (is (= (j/month :january) - (j/minus (j/month 5) 4) - (j/minus (j/month 5) (j/months 4)))))) - - (testing "day of week" - (testing "plus" - (is (= (j/day-of-week :sunday) - (j/plus (j/day-of-week 1) 6) - (j/plus (j/day-of-week 1) (j/days 6))))) - - (testing "minus" - (is (= (j/day-of-week :monday) - (j/minus (j/day-of-week 6) 5) - (j/minus (j/day-of-week 6) (j/days 5))))))) - -(deftest ordering - - (testing "times" - (let [ldt (j/local-date-time clock) - ldt+5 (j/plus ldt (j/days 5))] - (is (j/after? ldt+5 ldt)) - (is (not (j/after? ldt ldt+5))) - (is (j/before? ldt ldt+5)) - (is (not (j/before? ldt+5 ldt))) - (is (j/not-after? ldt ldt)) - (is (j/not-after? ldt ldt+5)) - (is (not (j/not-after? ldt+5 ldt))) - (is (j/not-before? ldt ldt)) - (is (j/not-before? ldt+5 ldt)) - (is (not (j/not-before? ldt ldt+5)))) - - (let [ld (j/local-date clock) - ld+5 (j/plus ld (j/days 5))] - (is (j/after? ld+5 ld)) - (is (not (j/after? ld ld+5))) - (is (j/before? ld ld+5)) - (is (not (j/before? ld+5 ld))) - (is (j/not-after? ld ld)) - (is (j/not-after? ld ld+5)) - (is (not (j/not-after? ld+5 ld))) - (is (j/not-before? ld ld)) - (is (j/not-before? ld+5 ld)) - (is (not (j/not-before? ld ld+5)))) - - (let [lt (j/local-time clock) - lt+5 (j/plus lt (j/minutes 5))] - (is (j/after? lt+5 lt)) - (is (not (j/after? lt lt+5))) - (is (j/before? lt lt+5)) - (is (not (j/before? lt+5 lt))) - (is (j/not-after? lt lt)) - (is (j/not-after? lt lt+5)) - (is (not (j/not-after? lt+5 lt))) - (is (j/not-before? lt lt)) - (is (j/not-before? lt+5 lt)) - (is (not (j/not-before? lt lt+5)))) - - (let [zdt (j/zoned-date-time clock) - zdt+5 (j/plus zdt (j/minutes 5))] - (is (j/after? zdt+5 zdt)) - (is (not (j/after? zdt zdt+5))) - (is (j/before? zdt zdt+5)) - (is (not (j/before? zdt+5 zdt))) - (is (j/not-after? zdt zdt)) - (is (j/not-after? zdt zdt+5)) - (is (not (j/not-after? zdt+5 zdt))) - (is (j/not-before? zdt zdt)) - (is (j/not-before? zdt+5 zdt)) - (is (not (j/not-before? zdt zdt+5)))) - - (let [odt (j/offset-date-time clock) - odt+5 (j/plus odt (j/minutes 5))] - (is (j/after? odt+5 odt)) - (is (not (j/after? odt odt+5))) - (is (j/before? odt odt+5)) - (is (not (j/before? odt+5 odt))) - (is (j/not-after? odt odt)) - (is (j/not-after? odt odt+5)) - (is (not (j/not-after? odt+5 odt))) - (is (j/not-before? odt odt)) - (is (j/not-before? odt+5 odt)) - (is (not (j/not-before? odt odt+5)))) - - (let [ot (j/offset-time clock) - ot+5 (j/plus ot (j/minutes 5))] - (is (j/after? ot+5 ot)) - (is (not (j/after? ot ot+5))) - (is (j/before? ot ot+5)) - (is (not (j/before? ot+5 ot))) - (is (j/not-after? ot ot)) - (is (j/not-after? ot ot+5)) - (is (not (j/not-after? ot+5 ot))) - (is (j/not-before? ot ot)) - (is (j/not-before? ot+5 ot)) - (is (not (j/not-before? ot ot+5)))) - - (let [i (j/instant clock) - i+5 (j/plus i (j/minutes 5))] - (is (j/after? i+5 i)) - (is (not (j/after? i i+5))) - (is (j/before? i i+5)) - (is (not (j/before? i+5 i))) - (is (j/not-after? i i)) - (is (j/not-after? i i+5)) - (is (not (j/not-after? i+5 i))) - (is (j/not-before? i i)) - (is (j/not-before? i+5 i)) - (is (not (j/not-before? i i+5))))) - - (testing "clocks" - (let [fc (j/fixed-clock 0) - fc+1000 (j/fixed-clock 1000)] - (is (j/after? fc+1000 fc)) - (is (not (j/after? fc fc+1000))) - (is (j/before? fc fc+1000)) - (is (not (j/before? fc+1000 fc))) - (is (j/not-after? fc fc)) - (is (j/not-after? fc fc+1000)) - (is (not (j/not-after? fc+1000 fc))) - (is (j/not-before? fc fc)) - (is (j/not-before? fc+1000 fc)) - (is (not (j/not-before? fc fc+1000))))) - - (testing "fields" - (let [thursday (j/day-of-week :thursday) - saturday (j/day-of-week :saturday) - sunday (j/day-of-week :sunday)] - (is (j/after? saturday :thursday)) - (is (not (j/after? thursday :saturday))) - (is (j/before? saturday :sunday)) - (is (not (j/before? sunday :saturday))) - (is (j/not-after? saturday saturday)) - (is (j/not-after? saturday sunday)) - (is (not (j/not-after? sunday saturday))) - (is (j/not-before? saturday saturday)) - (is (j/not-before? sunday saturday)) - (is (not (j/not-before? saturday sunday)))) - - (let [january (j/month :january) - february (j/month :february) - march (j/month :march)] - (is (j/after? february :january)) - (is (not (j/after? january :february))) - (is (j/before? february :march)) - (is (not (j/before? march :february))) - (is (j/not-after? january january)) - (is (j/not-after? february march)) - (is (not (j/not-after? march february))) - (is (j/not-before? january january)) - (is (j/not-before? february january)) - (is (not (j/not-before? january february)))) - - (let [year-2009 (j/year 2009) - year-2010 (j/year 2010)] - (is (j/after? year-2010 2009)) - (is (not (j/after? year-2009 2010))) - (is (j/before? year-2009 2010)) - (is (not (j/before? year-2010 2009))) - (is (j/not-after? year-2010 year-2010)) - (is (j/not-after? year-2009 year-2010)) - (is (not (j/not-after? year-2010 year-2009))) - (is (j/not-before? year-2010 year-2010)) - (is (j/not-before? year-2010 year-2009)) - (is (not (j/not-before? year-2009 year-2010)))) - - (let [jan-1 (j/month-day 1 1) - apr-1 (j/month-day 4 1)] - (is (j/after? apr-1 jan-1)) - (is (not (j/after? jan-1 apr-1))) - (is (j/before? jan-1 apr-1)) - (is (not (j/before? apr-1 jan-1))) - (is (j/not-after? jan-1 jan-1)) - (is (j/not-after? jan-1 apr-1)) - (is (not (j/not-after? apr-1 jan-1))) - (is (j/not-before? jan-1 jan-1)) - (is (j/not-before? apr-1 jan-1)) - (is (not (j/not-before? jan-1 apr-1)))))) - -(deftest mock-clock - (testing "constructors" - (is (= (j/mock-clock) - (j/mock-clock 0) - (j/mock-clock 0 (j/zone-id))))) - - (let [utc-clock #(j/mock-clock % "UTC")] - (testing "accessors" - (let [clock (utc-clock 0)] - (is (= 0 (j/value clock))) - (is (= (j/zone-id "UTC") (j/zone-id clock))))) - - (testing "equality" - (is (= (utc-clock 0) (utc-clock 0))) - (is (= (hash (utc-clock 0)) (hash (utc-clock 0)))) - (is (not= (utc-clock 0) (utc-clock 1))) - (is (not= (utc-clock 0) (j/mock-clock 0 "GMT")))) - - (testing "advance" - (let [clock (utc-clock 0)] - (testing "by positive amount" - (j/advance-clock! clock (j/millis 1)) - (is (= 1 (j/value clock)))) - - (testing "by negative amount" - (j/advance-clock! clock (j/millis -1)) - (is (= 0 (j/value clock)))))) - - (testing "clone with a different zone" - (let [clock (utc-clock 0) - cloned-clock (j/with-zone clock "GMT")] - (is (not (identical? clock cloned-clock))) - (is (= (j/zone-id "GMT") (j/zone-id cloned-clock))) - (is (= (j/value cloned-clock) (j/value clock))) - - (j/advance-clock! cloned-clock (j/seconds 1)) - (is (= 1000 (j/value cloned-clock))) - (is (not= (j/value cloned-clock) (j/value clock))))) - - (testing "set" - (let [clock (utc-clock 0)] - (testing "into future" - (j/set-clock! clock 100) - (is (= 100 (j/value clock)))) - - (testing "into past" - (j/set-clock! clock 0) - (is (= 0 (j/value clock)))))))) - -(deftest properties - (testing "units" - (is (= (j/unit :seconds) - (j/unit (j/duration) :seconds) - (j/unit (j/duration) (j/unit :seconds)))) - - (is (j/unit? (j/unit :seconds))) - - (is (j/supports? (j/duration) :seconds)) - (is (j/supports? :seconds (j/local-date-time))) - (is (not (j/supports? :seconds (j/local-date)))) - - (is (= 60 - (j/time-between (j/local-time "15:40") (j/local-time "15:41") :seconds) - (j/time-between :seconds (j/local-time "15:40") (j/local-time "15:41")) - (j/time-between (j/unit :seconds) (j/local-time "15:40") (j/local-time "15:41"))))) - - (testing "fields" - (is (= (j/field :second-of-day) - (j/field (j/local-date-time) :second-of-day) - (j/field (j/local-date-time) (j/field :second-of-day)))) - - (is (j/field? (j/field :second-of-day))) - - (is (j/supports? (j/local-date-time) :second-of-day)) - (is (j/supports? :second-of-day (j/local-date-time))) - (is (j/supports? :rata-die (j/local-date-time))) - (is (not (j/supports? :second-of-day (j/local-date)))) - - (testing ", ranges" - (is (= (j/value-range 0 86399) - (j/range :second-of-day))) - - (is (= (j/value-range {:min-smallest 1, :min-largest 1, :max-smallest 28, :max-largest 31}) - (j/range :day-of-month) - (j/range (j/field :day-of-month)))) - - (is (= 1 (j/min-value :day-of-month))) - (is (= 1 (j/largest-min-value :day-of-month))) - (is (= 28 (j/smallest-max-value :day-of-month))) - (is (= 31 (j/max-value :day-of-month))))) - - (testing "duration" - (let [d (j/duration 100000001)] - (is (= (j/properties d) - {:nanos (j/property d :nanos) - :seconds (j/property d :seconds)})) - (is (= (j/units d) - {:nanos (j/unit :nanos) - :seconds (j/unit :seconds)})))) - - (testing "period" - (let [p (j/period 10 5 1)] - (is (= (j/properties p) - {:days (j/property p :days) - :months (j/property p :months) - :years (j/property p :years)})) - (is (= (j/units p) - {:days (j/unit :days) - :months (j/unit :months) - :years (j/unit :years)})))) - - (testing "temporals" - (doseq [e [(j/local-date) - (j/local-time) - (j/local-date-time) - (j/offset-date-time) - (j/offset-time) - (j/zoned-date-time)]] - (is (seq (j/properties e))) - (is (seq (j/fields e))))) - - (testing "single fields" - (doseq [e [(j/month :february) - (j/day-of-week :monday) - (j/year 100) - (j/zone-offset 5 20)]] - (is (seq (j/properties e))) - (is (seq (j/fields e))) - (is (j/range e)))) - - (testing "multi fields" - (doseq [e [(j/month-day :january 1) - (j/year-month 10 10)]] - (is (seq (j/properties e))) - (is (seq (j/fields e)))))) - -(deftest seq-test - (is (= [(j/local-date 2015) (j/local-date 2016)] - (take 2 (j/iterate j/plus (j/local-date 2015) (j/years 1)))))) - -(deftest adjuster-test - (testing "predefined adjusters" - (is (= (j/adjust (j/local-date 2015 1 1) :first-in-month :monday) - (j/local-date 2015 1 5))) - - (is (= (j/adjust (j/local-date 2015 1 1) :day-of-week-in-month 1 :monday) - (j/local-date 2015 1 5))) - - (is (= (j/adjust (j/local-date 2015 1 1) :day-of-week-in-month 2 :monday) - (j/local-date 2015 1 12))) - - (is (= (j/adjust (j/local-date 2015 1 1) :first-day-of-next-year) - (j/local-date 2016 1 1)))) - - (testing "functions as adjusters" - (is (= (j/adjust (j/local-date 2015 1 1) j/plus (j/days 1)) - (j/local-date 2015 1 2))))) - -(deftest sugar-test - (testing "weekdays" - (is (j/monday? (j/local-date 2015 1 5))) - (is (j/tuesday? (j/offset-date-time 2015 1 6 0))) - (is (j/wednesday? (j/zoned-date-time 2015 1 7))) - (is (j/thursday? (j/local-date-time 2015 1 8))) - (is (j/friday? (j/day-of-week 5))) - (is (j/saturday? (j/day-of-week :saturday))) - (is (j/sunday? (j/day-of-week 7)))) - - (testing "predicates" - (is (j/weekday? (j/local-date 2015 1 5))) - (is (not (j/weekday? (j/local-date 2015 1 4)))) - (is (j/weekend? (j/local-date 2015 1 4))) - (is (not (j/weekend? (j/local-date 2015 1 5)))))) - -(deftest convert-test - (testing "amount" - (is (= {:remainder 10, :whole 0} - (j/convert-amount 10 :seconds :minutes))) - (is (= {:remainder 323200, :whole 16} - (j/convert-amount 10000000 :seconds :weeks))) - (is (thrown? Exception - (j/convert-amount 10 :seconds :years))) - (is (thrown? Exception - (j/convert-amount 10 :years :forever)))) - - (testing "as" - (testing "duration" - (is (= 0 (j/as (j/duration 10 :seconds) :minutes))) - (is (= 10 (j/as (j/duration 10 :seconds) :seconds))) - (is (= 10000 (j/as (j/duration 10 :seconds) :millis))) - (is (thrown? Exception (j/as (j/duration 10 :seconds) :months)))) - - (testing "period" - (is (= 0 (j/as (j/days 1) :weeks))) - (is (= (* 24 60) (j/as (j/days 1) :minutes))) - (is (thrown? Exception (j/as (j/months 1) :minutes))) - (is (thrown? Exception (j/as (j/period 1 1 1) :months))) - (is (= 13 (j/as (j/period 1 1) :months)))) - - (testing "temporal" - (is (= 1 (j/as (j/local-date 2015 1 1) :day-of-month))) - (is (= 2015 (j/as (j/local-date 2015 1 1) :year)))) - - (testing "temporal-accessor" - (let [month-day-under-test (j/month-day 3 31)] - (is (= 3 (j/as month-day-under-test :month-of-year))) - (is (= 31 (j/as month-day-under-test :day-of-month))) - (is (thrown? Exception (j/as month-day-under-test :year)))) - (let [year-month-under-test (j/year-month 2018 3)] - (is (= 2018 (j/as year-month-under-test :year))) - (is (= 3 (j/as year-month-under-test :month-of-year))) - (is (thrown? Exception (j/as year-month-under-test :day-of-month)))) - (let [zoned-date-time-test (j/zoned-date-time 2018 3)] - (is (= 1519830000 (j/as zoned-date-time-test :instant-seconds))))) - - (testing "multiple" - (is (= [2015 1 1] (j/as (j/local-date 2015 1 1) :year :month-of-year :day-of-month)))) - - (testing "throws" - (is (thrown? Exception (j/as (j/local-time 0) :year)))))) - -(deftest legacy-conversion - (testing "deprecated" - (testing "converts through instant" - (is (= (j/instant 1000) (j/instant (java.util.Date. 1000)))) - (is (= (java.util.Date. 1000) (j/to-java-date 1000))) - (is (= (java.sql.Date/valueOf (j/local-date 1000)) (j/to-sql-date 1000))) - (is (= (java.sql.Timestamp/valueOf (j/local-date-time 1000)) (j/to-sql-timestamp 1000))) - (is (= 1000 - (j/to-millis-from-epoch 1000) - (j/to-millis-from-epoch (java.util.Date. 1000)) - (j/to-millis-from-epoch (j/offset-date-time (j/instant 1000) +0))))) - - (testing "converts to java.util/sql Dates" - (is (= (java.util.Date. 1000) (j/to-java-date (j/instant 1000)))) - (is (= (java.sql.Date/valueOf (j/local-date 2016)) (j/to-sql-date (j/local-date 2016)))))) - - (testing "pre-java8" - (is (= (j/java-date (j/instant 1000)) - (java.util.Date. 1000) - (j/java-date 1000))) - (is (= (java.sql.Date/valueOf (j/local-date 2000 10 5)) - (j/sql-date 2000 10 5) - (j/sql-date (j/local-date 2000 10 5)))) - (is (= (java.sql.Timestamp/valueOf (j/local-date-time 2000 10 5 20 30 40)) - (j/sql-timestamp 2000 10 5 20 30 40) - (j/sql-timestamp (j/local-date-time 2000 10 5 20 30 40)))) - (is (= (java.sql.Timestamp/from (j/instant 1)) - (java.sql.Timestamp. 1) - (j/instant->sql-timestamp (j/instant 1)) - (j/instant->sql-timestamp 1))) - (is (= (java.sql.Time/valueOf (j/local-time 20 30 40)) - (j/sql-time 20 30 40) - (j/sql-time (j/local-time 20 30 40)))) - - (is (= (j/local-date 2000 10 5) (j/local-date (j/sql-date 2000 10 5)))) - (is (= (j/local-date-time 2000 10 5 20 30 40 1000) - (j/local-date-time (j/sql-timestamp 2000 10 5 20 30 40 1000)))) - (is (= (j/instant 1) (j/instant (j/instant->sql-timestamp 1)))) - (is (= (j/local-time 20 30 40) (j/local-time (j/sql-time 20 30 40))))) - - (testing "from java.util Date types" - (is (= (j/zone-id "UTC") (j/zone-id (java.util.TimeZone/getTimeZone "UTC")))))) - -(jt.u/when-threeten-extra - (testing "adjusters" - (is (= (j/adjust (j/local-date 2015 1 1) :next-working-day) - (j/local-date 2015 1 2)))) - - (testing "interval" - (is (= (j/interval "1970-01-01T00:00:00Z/1970-01-01T00:00:01Z") - (j/interval 0 1000) - (j/interval (j/offset-date-time 1970 1 1 0 0 0 0 +0) - (j/offset-date-time 1970 1 1 0 0 1 0 +0)))) - - (is (= 1 (j/as (j/interval (j/instant 0) (j/instant 1)) :millis))) - - (is (thrown-with-msg? IllegalArgumentException #"Cannot convert between.*" - (j/as (j/interval (j/instant 0) (j/instant 1)) :months)))) - - (testing "operations" - (is (= (j/interval 5000 10000) - (j/move-end-by (j/interval 5000 6000) (j/seconds 4)) - (j/move-start-by (j/interval 0 10000) (j/seconds 5)) - (j/move-end-to (j/interval 5000 6000) 10000) - (j/move-start-to (j/interval 0 10000) 5000))) - - (is (= (j/instant 0) (j/start (j/interval 0 1000)))) - (is (= (j/instant 1000) (j/end (j/interval 0 1000)))) - - (testing "contains" - (is (j/contains? (j/interval 0 1000) 500)) - (is (not (j/contains? (j/interval 0 1000) 1500))) - (is (j/contains? (j/interval 0 1000) (j/interval 100 900))) - (is (j/contains? (j/interval 0 1000) (j/interval 0 900))) - (is (j/contains? (j/interval 0 1000) (j/interval 0 1000))) - (is (j/contains? (j/interval 0 1000) (j/interval 1000 1000))) - (is (not (j/contains? (j/interval 0 1000) (j/interval 1000 1001))))) - - (testing "overlaps" - (is (j/overlaps? (j/interval 0 1000) (j/interval 0 500))) - (is (j/overlaps? (j/interval 0 1000) (j/interval 0 1500))) - (is (j/overlaps? (j/interval 500 1000) (j/interval 0 1500))) - (is (not (j/overlaps? (j/interval 0 1000) (j/interval 1500 2000)))) - - (is (= (j/interval 500 1000) (j/overlap (j/interval 500 1000) (j/interval 0 1500)))) - (is (nil? (j/overlap (j/interval 0 1000) (j/interval 1500 2000))))) - - (testing "abuts" - (is (j/abuts? (j/interval 0 1000) (j/interval 1000 2000))) - (is (not (j/abuts? (j/interval 0 1000) (j/interval 900 2000))))) - - (testing "gap" - (is (= (j/interval 1000 2000) (j/gap (j/interval 0 1000) (j/interval 2000 3000)))) - (is (nil? (j/gap (j/interval 0 1000) (j/interval 500 1500)))))) - - (testing "ordering" - (let [interval-1-2 (j/interval 1 2) - interval-3-4 (j/interval 3 4) - instant-1 (j/instant 1) - instant-3 (j/instant 3)] - (is (j/before? interval-1-2 interval-3-4)) - (is (not (j/before? interval-3-4 interval-1-2))) - (is (j/before? interval-1-2 instant-3)) - (is (not (j/before? interval-3-4 instant-1))) - - (is (j/after? interval-3-4 interval-1-2)) - (is (not (j/after? interval-1-2 interval-3-4))) - (is (j/after? interval-3-4 instant-1)) - (is (not (j/after? interval-1-2 instant-3))) - - (is (j/not-before? interval-3-4 interval-3-4)) - (is (not (j/not-before? interval-1-2 interval-3-4))) - (is (j/not-before? interval-3-4 instant-3)) - (is (j/not-before? interval-3-4 instant-1)) - (is (not (j/not-before? interval-1-2 instant-3))) - - (is (j/not-after? interval-1-2 interval-1-2)) - (is (j/not-after? interval-1-2 interval-3-4)) - (is (not (j/not-after? interval-3-4 interval-1-2))) - (is (j/not-after? interval-1-2 instant-1)) - (is (j/not-after? interval-1-2 instant-3)) - (is (not (j/not-after? interval-3-4 instant-1)))))) - -(jt.u/when-joda-time-loaded - - (def joda-clock (j/fixed-clock "2015-11-26T10:20:30.040Z" "UTC")) - - (import '[org.joda.time Duration Period DateTimeZone - LocalDate LocalTime LocalDateTime DateTime Instant]) - (deftest joda - (testing "duration from duration and period" - (is (= (j/duration 1 :millis) - (j/duration (Duration/millis 1)) - (j/duration (Period/millis 1)))) - (is (= (j/duration 1 :seconds) - (j/duration (Duration/standardSeconds 1)) - (j/duration (Period/seconds 1)))) - (is (= (j/duration 1 :minutes) - (j/duration (Duration/standardMinutes 1)) - (j/duration (Period/minutes 1)))) - (is (= (j/duration 1 :hours) - (j/duration (Duration/standardHours 1)) - (j/duration (Period/hours 1)))) - (is (= (j/duration 1 :days) - (j/duration (Duration/standardDays 1)) - (j/duration (Period/days 1)))) - - (is (= (j/plus (j/millis 1) (j/seconds 1) (j/minutes 1) (j/hours 1) - (j/standard-days 1)) - (j/duration (.plus (Duration/millis 1) - (.plus (Duration/standardSeconds 1) - (.plus (Duration/standardMinutes 1) - (.plus (Duration/standardHours 1) - (Duration/standardDays 1))))))))) - - (testing "duration from period" - (is (= (j/duration 7 :days) (j/duration (Period/weeks 1))))) - - (testing "period from duration" - (is (= (j/period 1 :days) (j/period (Duration/standardHours 24))))) - - (testing "period from joda period" - (is (= (j/period 1 :days) (j/period (Period/days 1)))) - (is (= (j/period 7 :days) (j/period (Period/weeks 1)))) - (is (= (j/period 1 :months) (j/period (Period/months 1)))) - (is (= (j/period 1 :years) (j/period (Period/years 1)))) - - (is (= (j/plus (j/days 1) (j/months 1) (j/years 1)) - (j/period (.plus (Period/days 1) - (.plus (Period/months 1) - (Period/years 1))))))) - - #_(testing "instant" - (is (= (j/instant joda-clock) - (j/instant (Instant. (DateTime. 2015 11 26 10 20 30)))))) - - (testing "local date" - (is (= (j/local-date joda-clock) - (j/local-date (LocalDate. 2015 11 26)) - (j/local-date (LocalDateTime. 2015 11 26 10 20 30)) - (j/local-date (DateTime. 2015 11 26 10 20 30))))) - - (testing "local date-time" - (is (= (j/local-date-time joda-clock) - (j/local-date-time (LocalDateTime. 2015 11 26 10 20 30 40)) - (j/local-date-time (DateTime. 2015 11 26 10 20 30 40))))) - - (testing "local time" - (is (= (j/local-time joda-clock) - (j/local-time (LocalTime. 10 20 30 40)) - (j/local-time (LocalDateTime. 2015 11 26 10 20 30 40)) - (j/local-time (DateTime. 2015 11 26 10 20 30 40))))) - - (testing "zoned date-time" - (is (= (j/zoned-date-time joda-clock) - (j/zoned-date-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))) - - (testing "offset date-time" - (is (= (j/offset-date-time joda-clock) - (j/offset-date-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))) - - (testing "offset time" - (is (= (j/offset-time joda-clock) - (j/offset-time (DateTime. 2015 11 26 10 20 30 40 (DateTimeZone/forID "UTC")))))))) - -(deftest locale-test - (let [current-locale (Locale/getDefault) - test-langs ["en" "tr" "cn"]] - (testing "locale specific rules for lower-case can cause formatters to not be found" - (doseq [lang test-langs] - (testing lang - (try - (Locale/setDefault (Locale/forLanguageTag lang)) - (is (some? (j/formatter :rfc-1123-date-time))) - (finally - (Locale/setDefault current-locale)))))))) - -(deftest formatter-test - (testing "case-insensitive formatter" - (let [fmt (java-time/formatter "hh:mma" {:case :insensitive})] - (is (= (j/local-time 0 34 0 0) - (j/local-time fmt "00:34am") - (j/local-time fmt "00:34AM"))))) - - (testing "case-sensitive formatter" - ;; Java version detection: - ;; java.lang.Runtime.Version class exists from Java 9 onwards, hence - ;; the need to detect the Java version from the java.version string returned - ;; by System/getProperty. In versions before 9, java.version has the format - ;; 1.x.y, e.g., 1.8.0_255, but from version 9 onwards, the initial 1 element - ;; is dropped. - ;; Refer to JEP 223 for information on the change. - ;; https://openjdk.java.net/jeps/223 - (let [java-version (->> (System/getProperty "java.version") - (re-find #"^\d+") - Integer/parseInt)] - (if (> java-version 11) - (testing "Java 12 and above treats AM as invalid" - (let [fmt (java-time/formatter "hh:mma" {:case :sensitive})] - (is (= (j/local-time 0 34 0 0) - (j/local-time fmt "12:34AM"))) - (is (thrown? Exception (j/local-time fmt "12:34am"))))) - - (testing "Java 8 and 11 treats am as invalid" - (let [fmt (java-time/formatter "hh:mma" {:case :sensitive})] - (is (= (j/local-time 0 34 0 0) - (j/local-time fmt "12:34AM"))) - (is (thrown? Exception (j/local-time fmt "12:34am"))))))))) + "Tests live in java-time.api-test, but we rename the + alias j to point to java-time here." + (:require [java-time :as j])) + +(with-open [rdr (-> (slurp "test/java_time/api_test.clj") + java.io.StringReader. + clojure.lang.LineNumberingPushbackReader.)] + (let [ns-form (read rdr) ;;rm ns form + _ (assert (= '(ns java-time.api-test + (:require [java-time.api :as j])) + (remove string? ns-form)) + (pr-str ns-form)) + s (str (slurp rdr) + "\n(assert (= *ns* (the-ns 'java-time-test)) *ns*)")] + #_ + (println "DEBUG\n" s) + (load-string s))) +(assert (= *ns* (the-ns 'java-time-test)) *ns*) +(assert (= #'java-time-test/constructors-test + (resolve 'constructors-test)) + (resolve 'constructors-test)) +(require 'java-time.api-test) +(assert (= (set (keys (ns-publics 'java-time-test))) + (set (keys (ns-publics 'java-time.api-test)))))