22
22
([test msg] `(when-not ~test (fail ~msg)))
23
23
([test] `(verify ~test ~(str " failed:" (pr-str test)))))
24
24
25
- (defmacro ^:private divisible?
25
+ (defn- divisible?
26
26
[num div]
27
- ` (zero? (mod ~ num~ div)))
27
+ (zero? (mod num div)))
28
28
29
- (defmacro ^:private indivisible?
29
+ (defn- indivisible?
30
30
[num div]
31
- ` (not (divisible? ~ num~ div)))
31
+ (not (divisible? num div)))
32
32
33
33
34
34
; ;; ------------------------------------------------------------------------
@@ -52,13 +52,13 @@ The function new-instant is called with the following arguments.
52
52
53
53
min max default
54
54
--- ------------ -------
55
- years 09'999 N/A (s must provide years)
55
+ years 0 9999 N/A (s must provide years)
56
56
months 1 12 1
57
57
days 1 31 1 (actual max days depends
58
58
hours 0 23 0 on month and year)
59
59
minutes 0 59 0
60
60
seconds 0 60 0 (though 60 is only valid
61
- nanoseconds 0999'999'999 0 when minutes is 59)
61
+ nanoseconds 0 999999999 0 when minutes is 59)
62
62
offset-sign -1 1 0
63
63
offset-hours 0 23 0
64
64
offset-minutes 0 59 0
@@ -88,10 +88,9 @@ Grammar (of s):
88
88
89
89
Unlike RFC3339:
90
90
91
- - we only consdier timestamp (was 'date-time')
92
- (removed: 'full-time', 'full-date')
91
+ - we only parse the timestamp format
93
92
- timestamp can elide trailing components
94
- - time-offset is optional
93
+ - time-offset is optional (defaults to +00:00)
95
94
96
95
Though time-offset is syntactically optional, a missing time-offset
97
96
will be treated as if the time-offset zero (+00:00) had been
@@ -158,52 +157,87 @@ with invalid arguments."
158
157
; ;; ------------------------------------------------------------------------
159
158
; ;; print integration
160
159
161
- ; ;;(defn- fixup-offset
162
- ; ;; [^String s]
163
- ; ;; (let [x (- (count s) 3)]
164
- ; ;; (str (.Substring s 0 x) ":" (.Substring s x)))) ;;; .substring
165
-
166
- (defn- caldate->rfc3339
167
- " format System.DateTime or System.DateTimeOffset as RFC3339 timestamp." ; ;; java.util.Date or java.util.Calendar
168
- [d]
169
- (format " #inst\" %1$tFT%1$tT.%1$tL%1$tz\" " d)); ;; took out fixup-offset wrapper call
160
+ ; ;;(def ^:private thread-local-utc-date-format
161
+ ; ;; ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access.
162
+ ; ;; ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335
163
+ ; ;; (proxy [ThreadLocal] []
164
+ ; ;; (initialValue []
165
+ ; ;; (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00")
166
+ ; ;; ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT)
167
+ ; ;; (.setTimeZone (java.util.TimeZone/getTimeZone "GMT"))))))
168
+
169
+ (defn- print-datetime ; ;; print-date
170
+ " Print a System.DateTime as RFC3339 timestamp, always in UTC." ; ;; java.util.Date
171
+ [ ^System.DateTime d, ^System.IO.TextWriter w]; ;; ^java.util.Date ^java.io.Writer
172
+ (let [utc-format" yyyy-MM-ddTHH:mm:ss.fff-00:00" ]; ;; (.get thread-local-utc-date-format)
173
+ (.Write w" #inst\" " ); ;; .write
174
+ (.Write w (.ToString d utc-format )); ;; (.write w (.format utc-format d))
175
+ (.Write w" \" " ))); ;; .write
176
+
177
+ ; ;; DM Added
178
+ (defn- print-datetimeoffset
179
+ " Print a System.DateTimeOffset as RFC3339 timestamp, always in UTC."
180
+ [ ^System.DateTimeOffset d, ^System.IO.TextWriter w]
181
+ (let [utc-format" yyyy-MM-ddTHH:mm:ss.fffzzzz" ]
182
+ (.Write w" #inst\" " )
183
+ (.Write w (.ToString d utc-format ))
184
+ (.Write w" \" " )))
185
+ ; ;;
170
186
171
187
(defmethod print-method System.DateTime ; ;; java.util.Date
172
188
[^System.DateTime d, ^System.IO.TextWriter w]; ;; ^java.util.Date ^java.io.Writer
173
- (.Write w ( caldate->rfc3339 d))) ; ;;.write
189
+ (print-datetime d w)) ; ;;print-date
174
190
175
191
(defmethod print-dup System.DateTime ; ;; java.util.Date
176
192
[^System.DateTime d, ^System.IO.TextWriter w]; ;; ^java.util.Date ^java.io.Writer
177
- (.Write w (caldate->rfc3339 d))); ;; .write
193
+ (print-datetime d w)); ;; print-date
194
+
195
+ ; ;;(defn- print-calendar
196
+ ; ;; "Print a java.util.Calendar as RFC3339 timestamp, preserving timezone."
197
+ ; ;; [^java.util.Calendar c, ^java.io.Writer w]
198
+ ; ;; (let [calstr (format "%1$tFT%1$tT.%1$tL%1$tz" c)
199
+ ; ;; offset-minutes (- (.length calstr) 2)]
200
+ ; ;; ;; calstr is almost right, but is missing the colon in the offset
201
+ ; ;; (.write w "#inst \"")
202
+ ; ;; (.write w calstr 0 offset-minutes)
203
+ ; ;; (.write w ":")
204
+ ; ;; (.write w calstr offset-minutes 2)
205
+ ; ;; (.write w "\"")))
178
206
179
207
(defmethod print-method System.DateTimeOffset ; ;; java.util.Calendar
180
- [^System.DateTimeOffsetc , ^System.IO.TextWriter w]; ;; ^java.util.Calendar ^java.io.Writer
181
- (.Write w ( caldate->rfc3339 c))) ; ;;.write
208
+ [^System.DateTimeOffsetd , ^System.IO.TextWriter w]; ;; ^java.util.Calendar ^java.io.Writer
209
+ (print-datetimeoffset d w)) ; ;;print-date
182
210
183
211
(defmethod print-dup System.DateTimeOffset ; ;; java.util.Calendar
184
- [^System.DateTimeOffset c, ^System.IO.TextWriter w]; ;; ^java.util.Calendar ^java.io.Writer
185
- (.Write w (caldate->rfc3339 c))); ;; .write
186
-
187
- (defn- fixup-nanos ; 0123456789012345678901234567890123456
188
- [^long nanos ^String s]; #@2011-01-01T01:00:00.000000000+01:00
189
- (str (.Substring s0 22 ); ;; .substring
190
- (format " %09d" nanos)
191
- (.Substring s31 ))); ;; .substring
192
-
193
- ; ;;(defn- timestamp->rfc3339
194
- ; ;; [^java.sql.Timestamp ts]
195
- ; ;; (->> ts
196
- ; ;; (format "#inst \"%1$tFT%1$tT.%1$tN%1$tz\"") ; %1$tN prints 9 digits for frac.
197
- ; ;; fixup-offset ; second, but last 6 are always
198
- ; ;; (fixup-nanos (.getNanos ts)))) ; 0 though timestamp has getNanos
212
+ [^System.DateTimeOffset d, ^System.IO.TextWriter w]; ;; ^java.util.Calendar ^java.io.Writer
213
+ (print-datetimeoffset d w)); ;; print-date
214
+
215
+ ; ;;(def ^:private thread-local-utc-timestamp-format
216
+ ; ;; ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access.
217
+ ; ;; ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335
218
+ ; ;; (proxy [ThreadLocal] []
219
+ ; ;; (initialValue []
220
+ ; ;; (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss")
221
+ ; ;; (.setTimeZone (java.util.TimeZone/getTimeZone "GMT"))))))
222
+
223
+ ; ;;(defn- print-timestamp
224
+ ; ;; "Print a java.sql.Timestamp as RFC3339 timestamp, always in UTC."
225
+ ; ;; [^java.sql.Timestamp ts, ^java.io.Writer w]
226
+ ; ;; (let [utc-format (.get thread-local-utc-timestamp-format)]
227
+ ; ;; (.write w "#inst \"")
228
+ ; ;; (.write w (.format utc-format ts))
229
+ ; ;; ;; add on nanos and offset
230
+ ; ;; ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT)
231
+ ; ;; (.write w (format ".%09d-00:00" (.getNanos ts)))
232
+ ; ;; (.write w "\"")))
199
233
200
234
; ;;(defmethod print-method java.sql.Timestamp
201
- ; ;; [^java.sql.Timestampt , ^java.io.Writer w]
202
- ; ;; (.write w (timestamp->rfc3339 t) ))
235
+ ; ;; [^java.sql.Timestampts , ^java.io.Writer w]
236
+ ; ;; (print-timestamp ts w ))
203
237
204
238
; ;;(defmethod print-dup java.sql.Timestamp
205
- ; ;; [^java.sql.Timestampt , ^java.io.Writer w]
206
- ; ;; (.write w (timestamp->rfc3339 t) ))
239
+ ; ;; [^java.sql.Timestampts , ^java.io.Writer w]
240
+ ; ;; (print-timestamp ts w ))
207
241
208
242
209
243
; ;; ------------------------------------------------------------------------
@@ -229,11 +263,11 @@ but truncating the subsecond fraction to milliseconds."
229
263
^DateTimeOffset
230
264
[years months days hours minutes seconds nanoseconds
231
265
offset-sign offset-hours offset-minutes]
232
- (DateTimeOffset. years months days hours minutes seconds
233
- (/ nanoseconds1000000 )
234
- (if (neg? offset-sign)
235
- (TimeSpan. (- offset-hours) (- offset-minutes)0 )
236
- (TimeSpan. offset-hours offset-minutes0 ))))
266
+ (DateTimeOffset. years months days hours minutes seconds
267
+ (/ nanoseconds1000000 )
268
+ (if (neg? offset-sign)
269
+ (TimeSpan. (- offset-hours) (- offset-minutes)0 )
270
+ (TimeSpan. offset-hours offset-minutes0 ))))
237
271
; ;;
238
272
239
273
@@ -252,7 +286,7 @@ but truncating the subsecond fraction to milliseconds."
252
286
milliseconds since the epoch, GMT."
253
287
[years months days hours minutes seconds nanoseconds
254
288
offset-sign offset-hours offset-minutes]
255
- (.LocalDateTime (construct-datetimeoffset years months days
289
+ (.UtcDateTime (construct-datetimeoffset years months days
256
290
hours minutes seconds nanoseconds
257
291
offset-sign offset-hours offset-minutes)))
258
292
; ;;
@@ -270,23 +304,28 @@ milliseconds since the epoch, GMT."
270
304
; ;; (.setNanos nanoseconds)))
271
305
272
306
(def read-instant-datetime ; ;; read-instant-date
273
- " Bind this to *instant-reader* to read instants as System.DateTime." ; ;; java.util.Date.
274
- (partial parse-timestamp (validated construct-datetime))); ;; construct-date
307
+ " To read an instant as a System.DateTime, bind *data-readers* to a map with
308
+ this var as the value for the 'inst key. The timezone offset will be used
309
+ to convert into UTC."
310
+ (partial parse-timestamp (validated construct-datetime))); ;; construct-date
275
311
276
312
; ;; DM: Added
277
313
(def read-instant-datetimeoffset
278
- " Bind this to *instant-reader* to read instants as System.DateTimeOffset."
279
- (partial parse-timestamp (validated construct-datetimeoffset)))
314
+ " To read an instant as a System.DateTimeOffset, bind *data-readers* to a map with
315
+ this var as the value for the 'inst key. The timezone offset will be used
316
+ to convert into UTC."
317
+ (partial parse-timestamp (validated construct-datetimeoffset)))
280
318
; ;;
281
319
282
320
; ;;(def read-instant-calendar
283
- ; ;; "Bind this to *instant-reader * toread instants as java.util.Calendar.
284
- ; ;;Calendar preserves thetimezone offset originally used in thedate
285
- ; ;;literal as written ."
286
- ; ;; (partial parse-timestamp (validated construct-calendar)))
321
+ ; ;;"To read an instant as a java.util.Calendar, bind *data-readers * toa map with
322
+ ; ;;this var as thevalue for the 'inst key. Calendar preserves thetimezone
323
+ ; ;;offset ."
324
+ ; ;; (partial parse-timestamp (validated construct-calendar)))
287
325
288
326
; ;;(def read-instant-timestamp
289
- ; ;; "Bind this to *instant-reader* to read instants as
290
- ; ;;java.sql.Timestamp. Timestamp preserves fractional seconds with
291
- ; ;;nanosecond precision."
292
- ; ;; (partial parse-timestamp (validated construct-timestamp)))
327
+ ; ;; "To read an instant as a java.sql.Timestamp, bind *data-readers* to a
328
+ ; ;;map with this var as the value for the 'inst key. Timestamp preserves
329
+ ; ;;fractional seconds with nanosecond precision. The timezone offset will
330
+ ; ;;be used to convert into UTC."
331
+ ; ;; (partial parse-timestamp (validated construct-timestamp)))