{"id":13591638,"url":"https://github.com/dm3/clojure.java-time","last_synced_at":"2025-05-14T03:03:06.240Z","repository":{"id":37951136,"uuid":"47488839","full_name":"dm3/clojure.java-time","owner":"dm3","description":"Java 8 Date-Time API for Clojure","archived":false,"fork":false,"pushed_at":"2024-11-16T00:32:04.000Z","size":905,"stargazers_count":474,"open_issues_count":22,"forks_count":47,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-03T09:04:41.343Z","etag":null,"topics":["clojure","interop","java-8","java-time","library"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dm3.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-12-06T08:12:48.000Z","updated_at":"2025-02-15T17:44:38.000Z","dependencies_parsed_at":"2023-11-16T04:25:42.533Z","dependency_job_id":"1d6e4fa9-52a7-4669-82c3-ca7f42ef1544","html_url":"https://github.com/dm3/clojure.java-time","commit_stats":{"total_commits":366,"total_committers":30,"mean_commits":12.2,"dds":0.7185792349726776,"last_synced_commit":"1bb34e6db3ea6829625cba094ab7247ddf3ef929"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dm3%2Fclojure.java-time","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dm3%2Fclojure.java-time/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dm3%2Fclojure.java-time/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dm3%2Fclojure.java-time/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dm3","download_url":"https://codeload.github.com/dm3/clojure.java-time/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248261916,"owners_count":21074225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","interop","java-8","java-time","library"],"created_at":"2024-08-01T16:01:00.081Z","updated_at":"2025-04-10T17:16:01.984Z","avatar_url":"https://github.com/dm3.png","language":"Clojure","funding_links":[],"categories":["Clojure","Date and Time"],"sub_categories":[],"readme":"# Clojure.Java-Time\n\n[![Clojars Project](https://img.shields.io/clojars/v/clojure.java-time.svg)](https://clojars.org/clojure.java-time)\n\nA Clojure wrapper for Java 8 Date-Time API.\n\n\u003e Note: This library has no relation to Clojure's (or Java's) core team.\n\u003e It's naming is legacy and preserved for backwards compatibility reasons.\n\n## Rationale\n\nMain goals:\n\n* Provide a consistent API for common operations with\n  instants, date-times, zones and periods.\n* Provide an escape hatch from Java types to clojure data structures.\n* Avoid reflective calls.\n* Provide an entry point into Java-Time by freeing the user from importing most\n  of the Java-Time classes.\n\nWhy use Clojure.Java-Time over [clj-time](https://github.com/clj-time/clj-time)\nor [Clojure.Joda-Time](https://github.com/dm3/clojure.joda-time)?\n\n* You don't want to have a dependency on the Joda-Time library\n* You already use Java 8\n* You prefer as little Java interop code as possible\n\nThis library employs a structured and comprehensive approach to exposing the\nJava 8 Date-Time API to the Clojure world. It's very similar to\nClojure.Joda-Time in its design goals and overall feeling, so if you ever used\nthat you will feel at home!\n\nWhy use Clojure.Java-Time over [cljc.java-time](https://github.com/henryw374/cljc.java-time) with [tick](https://github.com/juxt/tick)?\n\n* You only plan on running on the JVM\n* You prefer a single `require` over multiple ones\n\nI don't see any reasons except for aesthetical pleasure and existing knowledge to choose one \nover the other. However, I have neither used or benchmarked Cljc.Java-Time and Tick so my endorsement \nis purely on the merits of a broader feature set.\n\n## Documentation\n\n* [API](https://dm3.github.io/clojure.java-time/)\n* [![cljdoc badge](https://cljdoc.org/badge/clojure.java-time/clojure.java-time)](https://cljdoc.org/d/clojure.java-time/clojure.java-time/CURRENT)\n\n## What's different in Java Time API?\n\nIf you already used Joda Time before you might think: \"What in the world could\nthey do better?\". After all, Joda-Time already provides a pretty comprehensive\nset of tools for dealing with time-related concepts. Turns out, it's a tad more\ncomplicated than it has to be. Also, a few concepts have faulty designs which\nlead to hard to fix bugs and misuse. You can see the birds-eye view of changes\nand some of the rationale on the author's (Stephen Colebourne) blog:\n\n* [what's wrong with Joda-Time](https://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html),\n* [when you should use Java-Time](https://blog.joda.org/2014/07/threeten-backport-vs-joda-time.html)\n* [what's different in Java-Time](https://blog.joda.org/2014/11/converting-from-joda-time-to-javatime.html).\n\nYou can also take a look at a [comprehensive comparison](http://time4j.net/tutorial/appendix.html) by the\n[Time4J](http://time4j.net/) authors.\n\n## Usage\n\nAdd the following dependency to your `deps.edn`:\n```clj\nclojure.java-time/clojure.java-time {:mvn/version \"1.4.3\"}\n```\n\nor to your `project.clj` or `build.boot`:\n```clj\n[clojure.java-time \"1.4.3\"]\n```\n\nThe [API](https://dm3.github.io/clojure.java-time) of the Clojure.Java-Time\nconsists of one namespace, namely `java-time.api`.  For the purposes of this guide,\nwe will `require` the main namespace:\n\n```clj\n(require '[java-time.api :as jt]\n         ;; for REPL experimentation\n         'java-time.repl)\n```\n\n### Concept run-through\n\nThe Java Time API may seem daunting. Instead of a single `java.util.Date` you have\na `ZonedDateTime`, `OffsetDateTime`, `LocalDateTime`, `Instant`, and other\ntypes. You would be well served by reading the official documentation for the\n[Java Time API](https://docs.oracle.com/javase/tutorial/datetime/iso/index.html), \nbut we'll also do a quick run-through here.\n\n#### Local Dates and/or Times\n\n`LocalDate`, `LocalTime` and `LocalDateTime` are used to represent a date, time\nand date-time respectively without an offset or a time zone. The local time entities\nare used to represent human-based dates/times. They are a good fit for representing\nthe time of various events:\n\n* `LocalDate` - birthday, holiday\n    * see [`jt/local-date`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-date)\n* `LocalTime` - bus schedule, opening time of a shop\n    * see [`jt/local-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-time)\n* `LocalDateTime` - start of a competition\n    * see [`jt/local-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-local-date-time)\n\nExample usage:\n\n```clj\n(jt/local-date 2015 10)\n;=\u003e #\u003cjava.time.LocalDate 2015-10-01\u003e\n\n(jt/local-time 10)\n;=\u003e #\u003cjava.time.LocalTime 10:00\u003e\n\n(jt/local-date-time 2015 10)\n;=\u003e #\u003cjava.time.LocalDateTime 2015-10-01T00:00\u003e\n```\n\n#### Zoned Dates\n\nThere are two types which deal with zones: \n* `OffsetDateTime`\n  * see [`jt/offset-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-offset-date-time)\n* `ZonedDateTime`\n  * see [`jt/zoned-date-time`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-zoned-date-time)\n\nThey do pretty much what you would expect from their name.\nYou can think of the `Offset` time as a more concrete version of the `Zoned`\ntime. For example, the same time zone can have different offsets throughout the\nyear due to DST or governmental regulations.\n\n```clj\n(jt/offset-time 10)\n;=\u003e #\u003cjava.time.OffsetTime 10:00+01:00\u003e\n\n(jt/offset-date-time 2015 10)\n;=\u003e #\u003cjava.time.OffsetDateTime 2015-10-01T10:00+01:00\u003e\n\n(jt/zoned-date-time 2015 10)\n;=\u003e #\u003cjava.time.ZonedDateTime 2015-10-01T10:00+01:00[Europe/London]\u003e\n```\n\nOffset/Zone times only take the offset/zone as the last arguments for the\nmaximum arity constructor. You can influence the zone/offset by using the\n[`jt/with-zone`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-with-zone)\nor [`jt/with-offset`](https://dm3.github.io/clojure.java-time/java-time.api.html#var-with-offset) functions, like so:\n\n```clj\n(jt/with-zone (jt/zoned-date-time 2015 10) \"UTC\")\n;=\u003e #\u003cjava.time.ZonedDateTime 2015-10-01T00:00Z[UTC]\u003e\n\n(jt/with-zone-same-instant (jt/zoned-date-time 2015 10) \"UTC\")\n;=\u003e #\u003cjava.time.ZonedDateTime 2015-09-30T23:00Z[UTC]\u003e\n\n(jt/with-clock (jt/system-clock \"UTC\")\n  (jt/zoned-date-time 2015 10))\n;=\u003e #\u003cjava.time.ZonedDateTime 2015-10-01T00:00Z[UTC]\u003e\n```\n\n#### Instant\n\nAn `Instant` is used to generate a time stamp representing machine time. It\ndoesn't have an offset or a time zone. You can think of it as of a number of\nmilliseconds since epoch (`1970-01-01T00:00:00Z`). An instant is directly\nanalogous to `java.util.Date`:\n\n```clj\n(jt/instant)\n;=\u003e #\u003cjava.time.Instant \"2015-09-26T05:25:48.667Z\"\u003e\n\n(java.util.Date.)\n;=\u003e #inst \"2015-09-26T05:25:50.118-00:00\"\n```\n\nEvery other date entity can be converted to an instant (local ones will require\nan additional zone information).\n\n#### Period and Duration\n\nJava Time Period entities are considerably simpler than the Joda-Time periods.\nThey are fixed containers of years, months and days. You can use them to\nrepresent any period of time with a granularity larger or equal to a single day.\nDuration, on the other hand, represents a standard duration less than or equal\nto a single standard (24-hour) day.\n\n### Caution\nThe current incarnation of the library is relatively slow while calling the 2-3\narity `zoned-date-time/offset-time/offset-date-time` constructors for the\n*first time* in a given Clojure runtime. If you need predictable latency at the\ntime of the first call in your business logic, please warm the\nconstructors you are going to use up by calling them beforehand, e.g.:\n\n```clj\n(defn warm-up []\n  (jt/zoned-date-time 2015 1 1)\n  (jt/zoned-date-time 2015 1)\n  (jt/zoned-date-time 2015))\n```\n\nThe \"constructor\" here refers to an arity of a function together with its type\nsignature. For example, a `(jt/zoned-date-time 2015)` and `(jt/zoned-date-time (jt/system-clock))`\nare different constructors.\n\n### An appetizer\n\nFirst, let's do a quick run through common use cases.\n\nWhat is the current date?\n\n```clj\n(def now (jt/local-date))\n;=\u003e #object[java.time.LocalDate \"2015-09-27\"]\n```\n\nWhat's the next day?\n\n```clj\n(jt/plus now (jt/days 1))\n;=\u003e #object[java.time.LocalDate \"2015-09-28\"]\n```\n\nThe previous day?\n\n```clj\n(jt/minus now (jt/days 1))\n;=\u003e #object[java.time.LocalDate \"2015-09-26\"]\n```\n\nThree days starting at `now`?\n\n```clj\n(take 3 (jt/iterate jt/plus now (jt/days 1)))\n;=\u003e (#object[java.time.LocalDate \"2015-09-27\"]\n;    #object[java.time.LocalDate \"2015-09-28\"]\n;    #object[java.time.LocalDate \"2015-09-29\"])\n```\n\nWhen is the first Monday in month?\n\n```clj\n(jt/adjust now :first-in-month :monday)\n;=\u003e #object[java.time.LocalDate \"2015-09-07\"]\n```\n\nDate with some of its fields truncated:\n\n```clj\n(jt/truncate-to (jt/local-date-time 2015 9 28 10 15) :days)\n;=\u003e #object[java.time.LocalDateTime \"2015-09-28T00:00\"]\n```\n\nDate-time adjusted to the given hour:\n\n```clj\n(jt/adjust (jt/local-date-time 2015 9 28 10 15) (jt/local-time 6))\n;=\u003e #object[java.time.LocalDateTime \"2015-09-28T06:00\"]\n```\n\nThe latest of the given dates?\n\n```clj\n(jt/max (jt/local-date 2015 9 20) (jt/local-date 2015 9 28) (jt/local-date 2015 9 1))\n;=\u003e #object[java.time.LocalDate \"2015-09-28\"]\n```\n\nThe shortest of the given durations?\n\n```clj\n(jt/min (jt/duration 10 :seconds) (jt/duration 5 :hours) (jt/duration 3000 :millis))\n;=\u003e #object[java.time.Duration \"PT3S\"]\n```\n\nGet the year field out of the date:\n\n```clj\n(jt/as (jt/local-date 2015 9 28) :year)\n;=\u003e 2015\n```\n\nGet multiple fields:\n\n```clj\n(jt/as (jt/local-date 2015 9 28) :year :month-of-year :day-of-month)\n;=\u003e (2015 9 28)\n```\n\nGet the duration in a different unit:\n\n```clj\n(jt/plus (jt/hours 3) (jt/minutes 2))\n;=\u003e #object[java.time.Duration \"PT3H2M\"]\n\n(jt/as *1 :minutes)\n;=\u003e 182\n```\n\nFormat a date:\n\n```clj\n(jt/format \"MM/dd\" (jt/zoned-date-time 2015 9 28))\n;=\u003e \"09/28\"\n```\n\nParse a date:\n\n```clj\n(jt/local-date \"MM/yyyy/dd\" \"09/2015/28\")\n;=\u003e #object[java.time.LocalDate \"2015-09-28\"]\n```\n\nZoned date-times and offset date-times/times always take the zone/offset as the\nlast argument. Offsets can be specified as float values:\n\n```clj\n(jt/zone-offset +1.5)\n;=\u003e #\u003cjava.time.ZoneOffset +01:30\u003e\n\n(jt/zone-offset -1.5)\n;=\u003e #\u003cjava.time.ZoneOffset -01:30\u003e\n```\n\nCompare dates:\n\n```clj\n(jt/before? (jt/year 2020) (jt/year 2021))\n;=\u003e true\n\n(jt/after? (jt/year 2021) (jt/year 2021))\n;=\u003e false\n\n(let [expiration-date (jt/year 2010)\n      purchase-date (jt/year 2010)]\n  (jt/not-before? expiration-date purchase-date))\n;=\u003e true\n\n(let [start-date (jt/year 2011)\n      cutoff-date (jt/year 2010)]\n  (jt/not-after? start-date cutoff-date))\n;=\u003e false\n```\n\n#### Conversions\n\nTime entities can be converted to other time entities if the target contains\nless information, e.g. (assuming we're in UTC time zone):\n\n```clj\n(jt/zoned-date-time (jt/offset-date-time 2015 9 28 1))\n;=\u003e #object[java.time.ZonedDateTime \"2015-09-28T01:00Z\"]\n\n(jt/instant (jt/offset-date-time 2015 9 28 1))\n;=\u003e #object[java.time.Instant \"2015-09-28T01:00:00Z\"]\n\n(jt/offset-time (jt/offset-date-time 2015 9 28 1))\n;=\u003e #object[java.time.OffsetTime \"01:00Z\"]\n\n(jt/local-date-time (jt/offset-date-time 2015 9 28 1))\n;=\u003e #object[java.time.LocalDateTime \"2015-09-28T01:00\"]\n\n(jt/local-time (jt/offset-time 1))\n;=\u003e #object[java.time.LocalTime 0x3a3cd6d5 \"01:00\"]\n```\n\nConverting an Instant to ZonedDateTime requires a time zone:\n\n```clojure\n(jt/zoned-date-time (jt/instant 100) \"UTC\")\n;=\u003e #object[java.time.ZonedDateTime 0x291777c0 \"1970-01-01T00:00:00.100Z[UTC]\"]\n```\n\n#### Legacy Date-Time Types\n\nAny date which can be converted to an instant, can also be converted to a\n`java.util.Date`:\n\n```clojure\n(jt/java-date (jt/zoned-date-time 2015 9 28))\n;=\u003e #inst \"2015-09-27T22:00:00.000-00:00\"\n\n(jt/java-date 50000)\n;=\u003e #inst \"1970-01-01T00:00:50.000-00:00\"\n```\n\nAn instance of `java.util.Date` serves the same purpose as the new\n`java.time.Instant`. It's a machine timestamp which isn't aware of the\ntime zone. Please, do not get confused by the way it is printed by the Clojure\nprinter - the UTC time zone is applied during formatting.\n\nSometimes you'll have to work with the legacy `java.sql.{Date,Time,Timestamp}`\ntypes. The correspondence between the legacy types and the new Date-Time\nentities is as follows:\n\n  * `java.sql.Date`  \u003c-\u003e `java.time.LocalDate`\n  * `java.sql.Timestamp` \u003c-\u003e `java.time.LocalDateTime` \n  * `java.sql.Time` \u003c-\u003e `java.time.LocalTime`\n\n```clojure\n(jt/sql-date 2015 9 28)\n;=\u003e #inst \"2015-09-27T22:00:00.000-00:00\"\n\n(jt/sql-timestamp 2015 9 28 10 20 30 4000000)\n;=\u003e #inst \"2015-09-28T09:20:30.004-00:00\"\n\n(jt/sql-time 10 20 30)\n;=\u003e #inst \"1970-01-01T09:20:30.000-00:00\"\n```\n\nThe results of the above calls get printed as `#inst` because all of the\n`java.sql.{Date,Time,Timestamp}` are subtypes of `java.util.Date`.\nCoincidentally, this makes it impossible to plug the `java.sql.*` types into\nthe Clojure.Java-Time conversion graph.\n\nConversions to the legacy types also go the other way around:\n\n```clojure\n(jt/local-date (jt/sql-date 2015 9 28))\n;=\u003e #object[java.time.LocalDate \"2015-09-28\"]\n\n(jt/local-date-time (jt/sql-timestamp 2015 9 28 10 20 30 4000000))\n;=\u003e #object[java.time.LocalDateTime \"2015-09-28T10:20:30.004\"]\n\n(jt/local-time (jt/sql-time 10 20 30))\n;=\u003e #object[java.time.LocalTime \"10:20:30\"]\n```\n\n#### Three-Ten Extra\n\nIf you add an optional `[org.threeten/threeten-extra \"1.2\"]` dependency to the\nproject, you will get an `Interval`, `AmPm`, `DayOfMonth`, `DayOfYear`,\n`Quarter` and `YearQuarter` data types as well as a couple more adjusters.\n\nAn interval can be constructed from two entities that can be converted to\ninstants:\n\n```clojure\n(jt/interval (jt/offset-date-time 2015 1 1) (jt/zoned-date-time 2016 1 1))\n;=\u003e #\u003corg.threeten.extra.Interval 2015-01-01T00:00:00Z/2016-01-01T00:00:00Z\u003e\n\n(jt/move-start-by *1 (jt/duration 5 :days))\n;=\u003e #\u003corg.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-01T00:00:00Z\u003e\n\n(jt/move-end-by *1 (jt/duration 5 :days))\n;=\u003e #\u003corg.threeten.extra.Interval 2015-01-06T00:00:00Z/2016-01-06T00:00:00Z\u003e\n\n(jt/contains? *1 (jt/offset-date-time 2015 1 1))\n;=\u003e false\n```\n\n#### Joda-Time\n\nBonus! If you have Joda Time on the classpath (either directly, or via\n`clj-time`), you can seamlessly convert from Joda Time to Java Time types:\n\n```clojure\n(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)\n;=\u003e {:cost 2.0,\n;    :path [[#\u003cjava_time.graph.Types@15e43c24 [org.joda.time.DateTime]\u003e\n;            #\u003cjava_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]\u003e]\n;           [#\u003cjava_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]\u003e\n;            #\u003cjava_time.graph.Types@5360f6ae [java.time.OffsetTime]\u003e]]}\n\n(jt/offset-time (org.joda.time.DateTime/now))\n;=\u003e #\u003cjava.time.OffsetTime 22:00:00.000000000-00:00\u003e\n```\n\nClojure 1.9 added an [Inst](https://clojuredocs.org/clojure.core/inst_q)\nprotocol which is implemented for `java.util.Date` and `java.time.Instant` by\ndefault. If you're stuck on Joda-Time, you can extend the\n`org.joda.time.ReadableInstant`, which includes both `Instant` and `DateTime`\nusing the following:\n\n```clojure\n(jt/when-joda-time-loaded\n  (extend-type org.joda.time.ReadableInstant\n    Inst (inst-ms* [inst] (.getMillis inst))))\n```\n\nThis snippet isn't included in the Clojure.Java-Time code by default as both\nthe `Inst` protocol and the Joda-Time types are external to the library.\n\n#### Clocks\n\nJava Time introduced a concept of `Clock` - a time entity which can seed the\ndates, times and zones. However, there's no built-in facility which would allow\nyou to influence the date-times created using default constructors à la Joda's\n`DateTimeUtils/setCurrentMillisSystem`. Clojure.Java-Time tries to fix that with\nthe `with-clock` macro and the corresponding `with-clock-fn` function:\n\n```clojure\n(jt/zone-id)\n;=\u003e #\u003cjava.time.ZoneRegion Europe/London\u003e\n\n(jt/with-clock (jt/system-clock \"UTC\")\n  (jt/zone-id))\n;=\u003e #\u003cjava.time.ZoneRegion UTC\u003e\n```\n\nIn addition to the built-in `java.time` clocks, we provide a Mock clock which\ncan be very handy in testing:\n\n```clojure\n(def clock (jt/mock-clock 0 \"UTC\"))\n;=\u003e #'user/clock\n\n(jt/with-clock clock\n  (jt/instant))\n;=\u003e #object[java.time.Instant \"1970-01-01T00:00:00Z\"]\n\n(jt/advance-clock! clock (jt/plus (jt/hours 5) (jt/minutes 20)))\n;=\u003e nil\n\n(jt/with-clock clock\n  (jt/instant))\n;=\u003e #object[java.time.Instant \"1970-01-01T05:20:00Z\"]\n\n(jt/set-clock! clock 0)\n;=\u003e nil\n\n(jt/with-clock clock\n  (jt/instant))\n;=\u003e #object[java.time.Instant \"1970-01-01T00:00:00Z\"]\n```\n\nClock overrides works for all of the date-time types.\n\n#### Fields, Units and Properties\n\nDate-Time entities are composed of date fields, while Duration entities are\ncomposed of time units. You can see all of the predefined fields and units\nvia the `java-time.repl` ns:\n\n```clojure\n(java-time.repl/show-fields)\n;=\u003e (:aligned-day-of-week-in-month\n;    :aligned-day-of-week-in-year\n;    :aligned-week-of-month\n;    :aligned-week-of-year\n;    :am-pm-of-day\n;    :clock-hour-of-am-pm\n;    ...)\n```\n\n```clojure\n(java-time.repl/show-units)\n;=\u003e (:centuries\n;    :days\n;    :decades\n;    :eras\n;    :forever\n;    :half-days\n;    ...)\n```\n\nYou can obtain any field/unit like this:\n\n```clojure\n(jt/field :year)\n;=\u003e #object[java.time.temporal.ChronoField \"Year\"]\n\n(jt/unit :days)\n;=\u003e #object[java.time.temporal.ChronoUnit \"Days\"]\n\n(jt/field (jt/local-date 2015) :year)\n;=\u003e #object[java.time.temporal.ChronoField \"Year\"]\n```\n\nYou can obtain all of the fields/units of the temporal entity:\n\n```clojure\n(jt/fields (jt/local-date))\n;=\u003e {:proleptic-month #object[java.time.temporal.ChronoField ...}\n\n(jt/units (jt/duration))\n;=\u003e {:seconds #object[java.time.temporal.ChronoUnit \"Seconds\"],\n;    :nanos #object[java.time.temporal.ChronoUnit \"Nanos\"]}\n```\n\nBy themselves the fields and units aren't very interesting. You can get the\nrange of valid values for a field and a duration between two dates, but that's\nabout it:\n\n```clojure\n(jt/range (jt/field :year))\n;=\u003e #object[java.time.temporal.ValueRange \"-999999999 - 999999999\"]\n\n(jt/range (jt/field :day-of-month))\n;=\u003e #object[java.time.temporal.ValueRange \"1 - 28/31\"]\n\n(jt/time-between (jt/local-date 2015 9) (jt/local-date 2015 9 28) :days)\n;=\u003e 27\n```\n\nFields and units become interesting in conjunction with properties. Java-Time\ndoesn't support the concept of properties which is present in Joda-Time. There\nare reasons for that which I feel are only valid in a statically-typed API like\nJava's. In Clojure, properties allow expressing time entity modifications and\nqueries uniformly across all of the entity types.\n\n```clojure\n(def prop (jt/property (jt/local-date 2015 2 28) :day-of-month))\n;=\u003e #java_time.temporal.TemporalFieldProperty{...}\n\n(jt/value prop)\n;=\u003e 28\n\n(jt/with-min-value prop)\n;=\u003e #object[java.time.LocalDate \"2015-02-01\"]\n\n(jt/with-value prop 20)\n;=\u003e #object[java.time.LocalDate \"2015-02-20\"]\n\n(jt/with-max-value prop)\n;=\u003e #object[java.time.LocalDate \"2015-02-28\"]\n\n(jt/properties (jt/local-date 2015 9 28))\n;=\u003e {:proleptic-month #java_time.temporal.TemporalFieldProperty{...}, ...}\n```\n\n## Implementation Details\n\nMost of the temporal entity constructors with arities 1 to 3 use the conversion\ngraph underneath. This provides for a very flexible way of defining the\nconversions while avoiding huge conditional statements and multiple definitions\nof the identical conversion logic. However, the flexibility comes with a cost:\n\n1. The first call to a constructor will take a _long_ time as it will try to\n   find a path in the conversion graph. Subsequent calls will reuse the path.\n2. It's not trivial to evaluate the impact of adding and removing conversions\n   both on the performance and the conversion path chosen for certain arguments.\n3. You might get nonsensical results for some of the paths in the graph that\n   you might expect would make sense.\n\nHopefully, the performance issue will be resolved in the future...\n\nYou can play with the conversion graph using the following helpers:\n\n```clojure\n(java-time.repl/show-path org.joda.time.DateTime java.time.OffsetTime)\n;=\u003e {:cost 2.0,\n;    :path [[#\u003cjava_time.graph.Types@15e43c24 [org.joda.time.DateTime]\u003e\n;            #\u003cjava_time.graph.Types@78a2235c [java.time.Instant java.time.ZoneId]\u003e]\n;           [#\u003cjava_time.graph.Types@6d8ded1a [java.time.Instant java.time.ZoneId]\u003e\n;            #\u003cjava_time.graph.Types@5360f6ae [java.time.OffsetTime]\u003e]]}\n\n(java-time.repl/show-graph)\n;=\u003e {1\n;    {org.threeten.extra.DayOfYear\n;     [[#object[java_time.graph.Types \"[java.lang.Number]\"]\n;       #object[java_time.graph.Conversion \"Cost:1.0\"]]],\n;     java.lang.Number\n;     [[#object[java_time.graph.Types \"[java.time.Instant]\"]\n;       #object[java_time.graph.Conversion \"Cost:1.0\"]]\n;     ...}}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdm3%2Fclojure.java-time","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdm3%2Fclojure.java-time","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdm3%2Fclojure.java-time/lists"}