├── .gitignore ├── LICENSE ├── README.md ├── project.clj └── src ├── data_readers.clj └── java_time_literals └── core.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /.nrepl-port 2 | /target 3 | /pom.xml 4 | /pom.xml.asc 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | License: BSD 2 | Copyright © 2018+ Magnar Sveen. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # java-time-literals 2 | 3 | A Clojure library that defines literals for 4 | [java.time](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) 5 | classes. 6 | 7 | It does this by registering edn tags for reading, and adding handlers for 8 | `clojure.core/print-method` and `clojure.core/print-dup`. 9 | 10 | ## Install 11 | 12 | Add `[java-time-literals "2018-04-06"]` to `:dependencies` in your `project.clj`. 13 | 14 | ## Usage 15 | 16 | Require the library and start using literals: 17 | 18 | ```clj 19 | (require 'java-time-literals.core) 20 | 21 | #time/dur "PT15M" ;; Duration 22 | #time/inst "2007-12-03T10:15:30.00Z" ;; Instant 23 | #time/ld "2007-12-03" ;; LocalDate 24 | #time/ldt "2007-12-03T10:15:30" ;; LocalDateTime 25 | #time/lt "10:15:30" ;; LocalTime 26 | #time/md "--12-03" ;; MonthDay 27 | #time/odt "2007-12-03T10:15:30+01:00" ;; OffsetDateTime 28 | #time/ot "10:15:30+01:00" ;; OffsetTime 29 | #time/period "P3M" ;; Period 30 | #time/y "2007" ;; Year 31 | #time/ym "2007-12" ;; YearMonth 32 | #time/zdt "2007-12-03T10:15:30+01:00[Europe/Paris]" ;; ZonedDateTime 33 | #time/zid "Europe/Paris" ;; ZoneId 34 | #time/zoffset "+02:00" ;; ZoneOffset 35 | ``` 36 | 37 | You'll notice that most of these are quite short. The idea is that you're using 38 | literals to keep things terse. Readability comes as much from the format string 39 | as the tag name. 40 | 41 | ### Require vs injection 42 | 43 | If you want to use these literals in your tests, but don't have a natural main 44 | function or entry point to hold the require, you might find yourself requiring 45 | the namespace again and again. Instead, you can add an injection to your 46 | `project.clj`: 47 | 48 | ```clj 49 | :injections [(require 'java-time-literals.core)] 50 | ``` 51 | 52 | ### Enums 53 | 54 | Enum tags are represented with keywords. 55 | 56 | ```clj 57 | ;; ChronoUnit 58 | 59 | #time/unit :centuries 60 | #time/unit :days 61 | #time/unit :decades 62 | #time/unit :eras 63 | #time/unit :forever 64 | #time/unit :half-days 65 | #time/unit :hours 66 | #time/unit :micros 67 | #time/unit :millennia 68 | #time/unit :millis 69 | #time/unit :minutes 70 | #time/unit :months 71 | #time/unit :nanos 72 | #time/unit :seconds 73 | #time/unit :weeks 74 | #time/unit :years 75 | 76 | ;; ChronoField 77 | 78 | #time/field :aligned-day-of-week-in-month 79 | #time/field :aligned-day-of-week-in-year 80 | #time/field :aligned-week-of-month 81 | #time/field :aligned-week-of-year 82 | #time/field :ampm-of-day 83 | #time/field :clock-hour-of-ampm 84 | #time/field :clock-hour-of-day 85 | #time/field :day-of-month 86 | #time/field :day-of-week 87 | #time/field :day-of-year 88 | #time/field :epoch-day 89 | #time/field :era 90 | #time/field :hour-of-ampm 91 | #time/field :hour-of-day 92 | #time/field :instant-seconds 93 | #time/field :micro-of-day 94 | #time/field :micro-of-second 95 | #time/field :milli-of-day 96 | #time/field :milli-of-second 97 | #time/field :minute-of-day 98 | #time/field :minute-of-hour 99 | #time/field :month-of-year 100 | #time/field :nano-of-day 101 | #time/field :nano-of-second 102 | #time/field :offset-seconds 103 | #time/field :proleptic-month 104 | #time/field :second-of-day 105 | #time/field :second-of-minute 106 | #time/field :year 107 | #time/field :year-of-era 108 | 109 | ;; Month 110 | 111 | #time/month :january 112 | #time/month :february 113 | #time/month :march 114 | #time/month :april 115 | #time/month :may 116 | #time/month :june 117 | #time/month :july 118 | #time/month :august 119 | #time/month :september 120 | #time/month :october 121 | #time/month :november 122 | #time/month :december 123 | 124 | ;; DayOfWeek 125 | 126 | #time/day :monday 127 | #time/day :tuesday 128 | #time/day :wednesday 129 | #time/day :thursday 130 | #time/day :friday 131 | #time/day :saturday 132 | #time/day :sunday 133 | ``` 134 | 135 | ## License 136 | 137 | Copyright © (iterate inc 2018) Magnar Sveen 138 | 139 | [BSD-3-Clause](http://opensource.org/licenses/BSD-3-Clause), see LICENSE 140 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject java-time-literals "2018-04-06" 2 | :description "A Clojure library that defines literals for java.time classes." 3 | :url "https://github.com/magnars/java-time-literals" 4 | :license {:name "BSD-3-Clause" 5 | :url "http://opensource.org/licenses/BSD-3-Clause"} 6 | :dependencies [] 7 | :profiles {:dev {:dependencies [[org.clojure/clojure "1.8.0"]] 8 | :plugins [] 9 | :source-paths ["dev"]}}) 10 | -------------------------------------------------------------------------------- /src/data_readers.clj: -------------------------------------------------------------------------------- 1 | {time/dur java-time-literals.core/parse-duration 2 | time/inst java-time-literals.core/parse-instant 3 | time/ld java-time-literals.core/parse-local-date 4 | time/ldt java-time-literals.core/parse-local-date-time 5 | time/lt java-time-literals.core/parse-local-time 6 | time/md java-time-literals.core/parse-month-day 7 | time/odt java-time-literals.core/parse-offset-date-time 8 | time/ot java-time-literals.core/parse-offset-time 9 | time/period java-time-literals.core/parse-period 10 | time/y java-time-literals.core/parse-year 11 | time/ym java-time-literals.core/parse-year-month 12 | time/zdt java-time-literals.core/parse-zoned-date-time 13 | time/zid java-time-literals.core/parse-zone-id 14 | time/zoffset java-time-literals.core/parse-zone-offset 15 | 16 | ;; enums 17 | time/unit java-time-literals.core/chrono-units 18 | time/field java-time-literals.core/chrono-fields 19 | time/month java-time-literals.core/months 20 | time/day java-time-literals.core/days-of-week} 21 | -------------------------------------------------------------------------------- /src/java_time_literals/core.clj: -------------------------------------------------------------------------------- 1 | (ns java-time-literals.core 2 | (:import java.io.Writer 3 | [java.time DayOfWeek Duration Instant LocalDate LocalDateTime LocalTime Month MonthDay OffsetDateTime OffsetTime Period Year YearMonth ZonedDateTime ZoneId ZoneOffset] 4 | [java.time.temporal ChronoField ChronoUnit])) 5 | 6 | (comment 7 | (set! *warn-on-reflection* true)) 8 | 9 | (defmacro define-tag [tag label class parse-fn-name parse-param-class] 10 | (let [s (gensym) 11 | this (gensym) 12 | w (gensym)] 13 | `(do 14 | (defn ~(symbol (str "parse-" label)) {:tag ~class} [~(with-meta s {:tag parse-param-class})] 15 | (~(symbol (name class) parse-fn-name) ~s)) 16 | 17 | (defmethod print-method ~class [~(with-meta this {:tag class}) ~(with-meta w {:tag 'java.io.Writer})] 18 | (.write ~w ~(str tag " \"")) 19 | (.write ~w (.toString ~this)) 20 | (.write ~w "\"")) 21 | 22 | (defmethod print-dup ~class [~(with-meta this {:tag class}) ~(with-meta w {:tag 'java.io.Writer})] 23 | (.write ~w ~(str "#=(" *ns* "/parse-" label " \"")) 24 | (.write ~w (.toString ~this)) 25 | (.write ~w "\")"))))) 26 | 27 | (define-tag "#time/dur" duration Duration "parse" CharSequence) 28 | (define-tag "#time/inst" instant Instant "parse" CharSequence) 29 | (define-tag "#time/ld" local-date LocalDate "parse" CharSequence) 30 | (define-tag "#time/ldt" local-date-time LocalDateTime "parse" CharSequence) 31 | (define-tag "#time/lt" local-time LocalTime "parse" CharSequence) 32 | (define-tag "#time/md" month-day MonthDay "parse" CharSequence) 33 | (define-tag "#time/odt" offset-date-time OffsetDateTime "parse" CharSequence) 34 | (define-tag "#time/ot" offset-time OffsetTime "parse" CharSequence) 35 | (define-tag "#time/period" period Period "parse" CharSequence) 36 | (define-tag "#time/y" year Year "parse" CharSequence) 37 | (define-tag "#time/ym" year-month YearMonth "parse" CharSequence) 38 | (define-tag "#time/zdt" zoned-date-time ZonedDateTime "parse" CharSequence) 39 | (define-tag "#time/zid" zone-id ZoneId "of" String) 40 | (define-tag "#time/zoffset" zone-offset ZoneOffset "of" String) 41 | 42 | (comment 43 | #time/dur "PT15M" 44 | #time/inst "2007-12-03T10:15:30.00Z" 45 | #time/ld "2007-12-03" 46 | #time/ldt "2007-12-03T10:15:30" 47 | #time/lt "10:15:30" 48 | #time/md "--12-03" 49 | #time/odt "2007-12-03T10:15:30+01:00" 50 | #time/ot "10:15:30+01:00" 51 | #time/period "P3M" 52 | #time/y "2007" 53 | #time/ym "2007-12" 54 | #time/zdt "2007-12-03T10:15:30+01:00[Europe/Paris]" 55 | #time/zid "Europe/Paris" 56 | #time/zoffset "+02:00") 57 | 58 | (defmacro define-enum [tag label class enum-map] 59 | (let [s (gensym) 60 | this (gensym) 61 | w (gensym) 62 | lookup (gensym) 63 | reverse-lookup (gensym)] 64 | `(do 65 | (def ~lookup ~enum-map) 66 | 67 | (def ~reverse-lookup 68 | (into {} (map (juxt second first) ~lookup))) 69 | 70 | (defn ~label [kw#] 71 | (or (~lookup kw#) 72 | (throw (Exception. (str kw# " is not a constant in enum " ~(str class) ))))) 73 | 74 | (defmethod print-method ~class [~this ~(with-meta w {:tag 'java.io.Writer})] 75 | (.write ~w (str ~tag " ")) 76 | (.write ~w (str (~reverse-lookup ~this)))) 77 | 78 | (defmethod print-dup ~class [~(with-meta this {:tag class}) ~(with-meta w {:tag 'java.io.Writer})] 79 | (.write ~w ~(str "#=(" *ns* "/" label " ")) 80 | (.write ~w (str (~reverse-lookup ~this))) 81 | (.write ~w ")"))))) 82 | 83 | (define-enum "#time/unit" chrono-units ChronoUnit 84 | {:centuries ChronoUnit/CENTURIES 85 | :days ChronoUnit/DAYS 86 | :decades ChronoUnit/DECADES 87 | :eras ChronoUnit/ERAS 88 | :forever ChronoUnit/FOREVER 89 | :half-days ChronoUnit/HALF_DAYS 90 | :hours ChronoUnit/HOURS 91 | :micros ChronoUnit/MICROS 92 | :millennia ChronoUnit/MILLENNIA 93 | :millis ChronoUnit/MILLIS 94 | :minutes ChronoUnit/MINUTES 95 | :months ChronoUnit/MONTHS 96 | :nanos ChronoUnit/NANOS 97 | :seconds ChronoUnit/SECONDS 98 | :weeks ChronoUnit/WEEKS 99 | :years ChronoUnit/YEARS}) 100 | 101 | (define-enum "#time/field" chrono-fields ChronoField 102 | {:aligned-day-of-week-in-month ChronoField/ALIGNED_DAY_OF_WEEK_IN_MONTH 103 | :aligned-day-of-week-in-year ChronoField/ALIGNED_DAY_OF_WEEK_IN_YEAR 104 | :aligned-week-of-month ChronoField/ALIGNED_WEEK_OF_MONTH 105 | :aligned-week-of-year ChronoField/ALIGNED_WEEK_OF_YEAR 106 | :ampm-of-day ChronoField/AMPM_OF_DAY 107 | :clock-hour-of-ampm ChronoField/CLOCK_HOUR_OF_AMPM 108 | :clock-hour-of-day ChronoField/CLOCK_HOUR_OF_DAY 109 | :day-of-month ChronoField/DAY_OF_MONTH 110 | :day-of-week ChronoField/DAY_OF_WEEK 111 | :day-of-year ChronoField/DAY_OF_YEAR 112 | :epoch-day ChronoField/EPOCH_DAY 113 | :era ChronoField/ERA 114 | :hour-of-ampm ChronoField/HOUR_OF_AMPM 115 | :hour-of-day ChronoField/HOUR_OF_DAY 116 | :instant-seconds ChronoField/INSTANT_SECONDS 117 | :micro-of-day ChronoField/MICRO_OF_DAY 118 | :micro-of-second ChronoField/MICRO_OF_SECOND 119 | :milli-of-day ChronoField/MILLI_OF_DAY 120 | :milli-of-second ChronoField/MILLI_OF_SECOND 121 | :minute-of-day ChronoField/MINUTE_OF_DAY 122 | :minute-of-hour ChronoField/MINUTE_OF_HOUR 123 | :month-of-year ChronoField/MONTH_OF_YEAR 124 | :nano-of-day ChronoField/NANO_OF_DAY 125 | :nano-of-second ChronoField/NANO_OF_SECOND 126 | :offset-seconds ChronoField/OFFSET_SECONDS 127 | :proleptic-month ChronoField/PROLEPTIC_MONTH 128 | :second-of-day ChronoField/SECOND_OF_DAY 129 | :second-of-minute ChronoField/SECOND_OF_MINUTE 130 | :year ChronoField/YEAR 131 | :year-of-era ChronoField/YEAR_OF_ERA}) 132 | 133 | (define-enum "#time/month" months Month 134 | {:january Month/JANUARY 135 | :february Month/FEBRUARY 136 | :march Month/MARCH 137 | :april Month/APRIL 138 | :may Month/MAY 139 | :june Month/JUNE 140 | :july Month/JULY 141 | :august Month/AUGUST 142 | :september Month/SEPTEMBER 143 | :october Month/OCTOBER 144 | :november Month/NOVEMBER 145 | :december Month/DECEMBER}) 146 | 147 | (define-enum "#time/day" days-of-week DayOfWeek 148 | {:monday DayOfWeek/MONDAY 149 | :tuesday DayOfWeek/TUESDAY 150 | :wednesday DayOfWeek/WEDNESDAY 151 | :thursday DayOfWeek/THURSDAY 152 | :friday DayOfWeek/FRIDAY 153 | :saturday DayOfWeek/SATURDAY 154 | :sunday DayOfWeek/SUNDAY}) 155 | 156 | --------------------------------------------------------------------------------