forked from dm3/clojure.java-time
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzone.clj
More file actions
443 lines (362 loc) · 12.8 KB
/
zone.clj
File metadata and controls
443 lines (362 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
(ns java-time.zone
(: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]
[java-time.format :as jt.f]
[java-time.clock :as jt.clock]
[java-time.properties :as jt.p :refer (get-unit-checked)]
[java-time.defconversion :refer (conversion! deffactory)])
(:import [java.time.temporal TemporalAccessor]
[java.time.format DateTimeFormatter]
[java.time Clock Instant LocalDate LocalTime LocalDateTime
ZoneId ZoneOffset OffsetDateTime OffsetTime ZonedDateTime]))
;;;;; Zone Id
(defn- to-hms [n]
(if (integer? n)
[n 0 0]
(let [h (int n)
m-n (* 60 (- n h))
m (int m-n)
s (int (* 60 (- m-n m)))]
[h m s])))
(conversion! java.util.TimeZone ZoneId
(fn [^java.util.TimeZone z]
(.toZoneId z)))
(conversion! CharSequence ZoneId
(fn [^CharSequence s]
(ZoneId/of s)))
(conversion! [CharSequence ZoneOffset] ZoneId
(fn [^CharSequence s, ^ZoneOffset zo]
(ZoneId/ofOffset s zo)))
(defn- ^ZoneOffset clock->zone-offset [^Clock c]
(-> (.getZone c)
(.getRules)
(.getOffset (.instant c))))
(deffactory zone-offset
"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."
:returns ZoneOffset
:implicit-arities []
([] (jt.clock/make clock->zone-offset))
([o] (cond (instance? ZoneOffset o)
o
(instance? Clock o)
(clock->zone-offset o)
(instance? java.time.temporal.TemporalAccessor o)
(ZoneOffset/from ^java.time.temporal.TemporalAccessor o)
(string? o)
(ZoneOffset/of ^String o)
(number? o)
(let [[h m s] (to-hms o)]
(zone-offset h m s))
:else (throw (java.time.DateTimeException.
(format "Could not convert %s to a ZoneOffset!" o)))))
([h m] (ZoneOffset/ofHoursMinutes h m))
([h m s] (ZoneOffset/ofHoursMinutesSeconds h m s)))
(deffactory zone-id
"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."
:returns ZoneId
:implicit-arities [1 2]
([] (jt.clock/make (fn [^Clock c] (.getZone c)))))
(defn available-zone-ids
"Returns a set of string identifiers for all available ZoneIds."
[]
(ZoneId/getAvailableZoneIds))
;; offset date/time
(deffactory offset-date-time
"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)`."
:returns OffsetDateTime
:implicit-arities [1 2 3]
([] (jt.clock/make (fn [^Clock c] (OffsetDateTime/now c))))
([y m d h] (offset-date-time y m d h 0))
([y mo d h m] (offset-date-time y mo d h m 0))
([y mo d h m s] (offset-date-time y mo d h m s 0))
([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 (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
"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)`."
:returns OffsetTime
:implicit-arities [1 2]
([] (jt.clock/make (fn [^Clock c] (OffsetTime/now c))))
([h m s] (offset-time h m s 0))
([h m s n] (offset-time h m s n (zone-offset)))
([h m s n o]
(OffsetTime/of h m s n (zone-offset o))))
(deffactory zoned-date-time
"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)`."
:returns ZonedDateTime
:implicit-arities [1 2 3]
([] (jt.clock/make (fn [^Clock c] (ZonedDateTime/now c))))
([y m d h] (zoned-date-time y m d h 0))
([y mo d h m] (zoned-date-time y mo d h m 0))
([y mo d h m s] (zoned-date-time y mo d h m s 0))
([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 (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
(fn [^Clock c]
(ZonedDateTime/now c)))
(conversion! Clock OffsetDateTime
(fn [^Clock c]
(OffsetDateTime/now c)))
(conversion! Clock OffsetTime
(fn [^Clock c]
(OffsetTime/now c)))
(conversion! ZoneId ZonedDateTime
(fn [^ZoneId z]
(jt.clock/make
(fn [^Clock c]
(ZonedDateTime/now (.withZone c z)))))
2)
(conversion! ZoneId OffsetDateTime
(fn [^ZoneId z]
(jt.clock/make
(fn [^Clock c]
(OffsetDateTime/now (.withZone c z)))))
2)
(conversion! ZoneId OffsetTime
(fn [^ZoneId z]
(jt.clock/make
(fn [^Clock c]
(OffsetTime/now (.withZone c z)))))
2)
(conversion! CharSequence ZonedDateTime
(fn [^CharSequence s]
(ZonedDateTime/parse s))
2)
(conversion! CharSequence OffsetDateTime
(fn [^CharSequence s]
(OffsetDateTime/parse s))
2)
(conversion! CharSequence OffsetTime
(fn [^CharSequence s]
(OffsetTime/parse s))
2)
(conversion! ZonedDateTime [Instant ZoneId]
(fn [^ZonedDateTime zdt]
[(.toInstant zdt) (.getZone zdt)]))
(conversion! OffsetDateTime [Instant ZoneOffset]
(fn [^OffsetDateTime odt]
[(.toInstant odt) (.getOffset odt)]))
(conversion! OffsetTime [LocalTime ZoneOffset]
(fn [^OffsetTime odt]
[(.toLocalTime odt) (.getOffset odt)]))
(conversion! OffsetTime OffsetDateTime
(fn [^OffsetTime ot]
(.atDate ot (LocalDate/now)))
2)
(conversion! [LocalDateTime ZoneOffset] OffsetDateTime
(fn [^LocalDateTime ldt, ^ZoneOffset zo]
(OffsetDateTime/of ldt zo)))
(conversion! [LocalDateTime ZoneId] ZonedDateTime
(fn [^LocalDateTime ldt, ^ZoneId z]
(ZonedDateTime/of ldt z)))
(conversion! [LocalTime ZoneOffset] OffsetTime
(fn [^LocalTime lt, ^ZoneOffset zo]
(OffsetTime/of lt zo)))
(conversion! [Instant ZoneId] ZonedDateTime
(fn [^Instant i, ^ZoneId z]
(ZonedDateTime/ofInstant i z)))
(conversion! [Instant ZoneId] OffsetDateTime
(fn [^Instant i, ^ZoneId z]
(OffsetDateTime/ofInstant i z)))
(conversion! [Instant ZoneId] OffsetTime
(fn [^Instant i, ^ZoneId z]
(OffsetTime/ofInstant i z)))
(conversion! [java.time.format.DateTimeFormatter CharSequence] ZonedDateTime
#(ZonedDateTime/from (jt.f/parse %1 %2)))
(conversion! [java.time.format.DateTimeFormatter CharSequence] OffsetDateTime
#(OffsetDateTime/from (jt.f/parse %1 %2)))
(conversion! [java.time.format.DateTimeFormatter CharSequence] OffsetTime
#(OffsetTime/from (jt.f/parse %1 %2)))
(conversion! Number ZonedDateTime
(fn [value]
(zoned-date-time value 1 1 0)))
(conversion! Number OffsetDateTime
(fn [value]
(offset-date-time value 1 1 0)))
(conversion! Number OffsetTime
(fn [value]
(offset-time value 0 0)))
(conversion! [Number Number] ZonedDateTime
(fn [y m]
(zoned-date-time y m 1 0)))
(conversion! [Number Number] OffsetDateTime
(fn [y m]
(offset-date-time y m 1 0)))
(conversion! [Number Number] OffsetTime
(fn [h m]
(offset-time h m 0)))
(conversion! [Number Number Number] ZonedDateTime
(fn [y m d]
(zoned-date-time y m d 0)))
(conversion! [Number Number Number] OffsetDateTime
(fn [y m d]
(offset-date-time y m d 0)))
(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]
"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 [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>"))
(extend-type OffsetDateTime
jt.c/Truncatable
(truncate-to [o u]
(.truncatedTo o (get-unit-checked u)))
HasOffset
(with-offset [o offset]
(.withOffsetSameLocal o (zone-offset offset)))
(with-offset-same-instant [o offset]
(.withOffsetSameInstant o (zone-offset offset)))
jt.c/Ordered
(single-after? [d o]
(.isAfter d o))
(single-before? [d o]
(.isBefore d o)))
(extend-type OffsetTime
jt.c/Truncatable
(truncate-to [o u]
(.truncatedTo o (get-unit-checked u)))
HasOffset
(with-offset [o offset]
(.withOffsetSameLocal o (zone-offset offset)))
(with-offset-same-instant [o offset]
(.withOffsetSameInstant o (zone-offset offset)))
jt.c/Ordered
(single-after? [d o]
(.isAfter d o))
(single-before? [d o]
(.isBefore d o)))
(extend-type ZonedDateTime
jt.c/Truncatable
(truncate-to [o u]
(.truncatedTo o (get-unit-checked u)))
jt.c/HasZone
(with-zone [o z]
(.withZoneSameLocal o (zone-id z))))
(defn with-zone-same-instant
"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]>"
[^ZonedDateTime zdt, z]
(.withZoneSameInstant zdt (zone-id z)))
;;;;; Clock
(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 ^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 ^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 ^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)))
([^Clock c, d] (Clock/tick c (jt.a/duration d))))
(defn clock?
"Returns true if `x` is an instance of `java.time.Clock`."
[x] (instance? Clock x))
(extend-type Clock
jt.c/ReadableProperty
(value [c] (.millis c))
jt.c/HasZone
(with-zone [c z]
(.withZone c (zone-id z)))
jt.c/Ordered
(single-after? [c o]
(> (.millis c) (.millis ^Clock o)))
(single-before? [c o]
(< (.millis c) (.millis ^Clock o))))
;; Avoid cyclic dep
(extend-type java.time.format.DateTimeFormatter
jt.c/HasZone
(with-zone [dtf zone]
(.withZone dtf (zone-id zone))))