@@ -238,77 +238,66 @@ end
238
238
# see https://github.com/invenia/LibPQ.jl/issues/33
239
239
_trunc_seconds (str) = replace (str, r" (\. [\d ]{3})\d +" => s "\g <1>" )
240
240
241
- _DEFAULT_TYPE_MAP[:timestamp ] = DateTime
242
- const TIMESTAMP_FORMAT = dateformat " y-m-d HH:MM:SS.s" # .s is optional here
243
- function pqparse (:: Type{DateTime} , str:: AbstractString )
241
+ # Utility function for handling "infinity" strings for datetime types to reduce duplication
242
+ function _tryparse_datetime_inf (
243
+ typ:: Type{T} , str, f= typ
244
+ ):: Union{T, Nothing} where T <: Dates.AbstractDateTime
244
245
if str == " infinity"
245
246
depwarn_timetype_inf ()
246
- return typemax (DateTime)
247
+ return f ( typemax (DateTime) )
247
248
elseif str == " -infinity"
248
249
depwarn_timetype_inf ()
249
- return typemin (DateTime)
250
+ return f ( typemin (DateTime) )
250
251
end
251
252
252
- # Cut off digits after the third after the decimal point,
253
- # since DateTime in Julia currently handles only milliseconds, see Issue #33
254
- str = replace (str, r" (\. [\d ]{3})\d +" => s "\g <1>" )
255
- return parse (DateTime, str, TIMESTAMP_FORMAT)
253
+ return nothing
254
+ end
255
+
256
+ _DEFAULT_TYPE_MAP[:timestamp ] = DateTime
257
+ const TIMESTAMP_FORMAT = dateformat " y-m-d HH:MM:SS.s" # .s is optional here
258
+ function pqparse (:: Type{DateTime} , str:: AbstractString )
259
+ parsed = _tryparse_datetime_inf (DateTime, str)
260
+ isnothing (parsed) || return parsed
261
+
262
+ parsed = tryparse (DateTime, str, TIMESTAMP_FORMAT)
263
+ isnothing (parsed) || return parsed
264
+
265
+ return parse (DateTime, _trunc_seconds (str), TIMESTAMP_FORMAT)
256
266
end
257
267
258
268
# ISO, YMD
259
269
_DEFAULT_TYPE_MAP[:timestamptz ] = ZonedDateTime
260
- const TIMESTAMPTZ_ZDT_FORMATS = (
270
+ const TIMESTAMPTZ_FORMATS = (
261
271
dateformat " y-m-d HH:MM:SSz" ,
262
272
dateformat " y-m-d HH:MM:SS.sz" ,
263
273
dateformat " y-m-d HH:MM:SS.ssz" ,
264
274
dateformat " y-m-d HH:MM:SS.sssz" ,
265
275
)
266
- const TIMESTAMPTZ_UTC_FORMATS = (
267
- dateformat " y-m-d HH:MM:SS" ,
268
- dateformat " y-m-d HH:MM:SS.s" ,
269
- dateformat " y-m-d HH:MM:SS.ss" ,
270
- dateformat " y-m-d HH:MM:SS.sss" ,
271
- )
272
276
273
- timestamptz_formats (:: Type{ZonedDateTime} ) = TIMESTAMPTZ_ZDT_FORMATS
274
- timestamptz_formats (:: Type{UTCDateTime} ) = TIMESTAMPTZ_UTC_FORMATS
277
+ function pqparse (:: Type{ZonedDateTime} , str:: AbstractString )
278
+ parsed = _tryparse_datetime_inf (ZonedDateTime, str, Base. Fix2 (ZonedDateTime, tz " UTC" ))
279
+ isnothing (parsed) || return parsed
275
280
276
- function _pqparse (:: Type{T} , str:: AbstractString ) where T<: Union{UTCDateTime, ZonedDateTime}
277
- formats = timestamptz_formats (T)
278
- for fmt in formats[1 : (end - 1 )]
279
- parsed = tryparse (T, str, fmt)
280
- parsed != = nothing && return parsed
281
+ for fmt in TIMESTAMPTZ_FORMATS[1 : (end - 1 )]
282
+ parsed = tryparse (ZonedDateTime, str, fmt)
283
+ isnothing (parsed) || return parsed
281
284
end
282
285
283
- return parse (T , _trunc_seconds (str), formats [end ])
286
+ return parse (ZonedDateTime , _trunc_seconds (str), TIMESTAMPTZ_FORMATS [end ])
284
287
end
285
288
286
- function pqparse (:: Type{ZonedDateTime} , str:: AbstractString )
287
- if str == " infinity"
288
- depwarn_timetype_inf ()
289
- return ZonedDateTime (typemax (DateTime), tz " UTC" )
290
- elseif str == " -infinity"
291
- depwarn_timetype_inf ()
292
- return ZonedDateTime (typemin (DateTime), tz " UTC" )
293
- end
289
+ function pqparse (:: Type{UTCDateTime} , str:: AbstractString )
290
+ parsed = _tryparse_datetime_inf (UTCDateTime, str)
291
+ isnothing (parsed) || return parsed
294
292
295
- return _pqparse (ZonedDateTime, str)
296
- end
293
+ # Postgres should always give us strings ending with +00 if our timezone is set to UTC
294
+ # which is the default
295
+ str = replace (str, " +00" => " " )
297
296
298
- function pqparse (:: Type{UTCDateTime} , str:: AbstractString )
299
- if str == " infinity"
300
- depwarn_timetype_inf ()
301
- return UTCDateTime (typemax (DateTime))
302
- elseif str == " -infinity"
303
- depwarn_timetype_inf ()
304
- return UTCDateTime (typemin (DateTime))
305
- end
297
+ parsed = tryparse (UTCDateTime, str, TIMESTAMP_FORMAT)
298
+ isnothing (parsed) || return parsed
306
299
307
- # Postgres should give us strings ending with +00, +00:00, -00:00
308
- # We use the regex below to strip these character off before parsing, iff,
309
- # the values after the `-`/`+` are `0` or `:`. This means parsing will fail if
310
- # we're asked to parse a non-UTC string like +04:00.
311
- return _pqparse (UTCDateTime, replace (str, r" [-|\+ ][0|:]*$" => " " ))
300
+ return parse (UTCDateTime, _trunc_seconds (str), TIMESTAMP_FORMAT)
312
301
end
313
302
314
303
_DEFAULT_TYPE_MAP[:date ] = Date
@@ -363,7 +352,7 @@ function Base.parse(::Type{ZonedDateTime}, pqv::PQValue{PQ_SYSTEM_TYPES[:int8]})
363
352
end
364
353
365
354
function Base. parse (:: Type{UTCDateTime} , pqv:: PQValue{PQ_SYSTEM_TYPES[:int8]} )
366
- return UTCDateTime (unix2datetime ( parse (Int64 , pqv) ))
355
+ return UTCDateTime (parse (DateTime , pqv))
367
356
end
368
357
369
358
# All postgresql timestamptz are stored in UTC time with the epoch of 2000-01-01.
@@ -387,16 +376,7 @@ function pqparse(::Type{ZonedDateTime}, ptr::Ptr{UInt8})
387
376
end
388
377
389
378
function pqparse (:: Type{UTCDateTime} , ptr:: Ptr{UInt8} )
390
- value = ntoh (unsafe_load (Ptr {Int64} (ptr)))
391
- if value == typemax (Int64)
392
- depwarn_timetype_inf ()
393
- return UTCDateTime (typemax (DateTime))
394
- elseif value == typemin (Int64)
395
- depwarn_timetype_inf ()
396
- return UTCDateTime (typemin (DateTime))
397
- end
398
- dt = POSTGRES_EPOCH_DATETIME + Microsecond (value)
399
- return UTCDateTime (dt)
379
+ return UTCDateTime (pqparse (DateTime, ptr))
400
380
end
401
381
402
382
function pqparse (:: Type{DateTime} , ptr:: Ptr{UInt8} )
@@ -408,7 +388,7 @@ function pqparse(::Type{DateTime}, ptr::Ptr{UInt8})
408
388
depwarn_timetype_inf ()
409
389
return typemin (DateTime)
410
390
end
411
- return POSTGRES_EPOCH_DATETIME + Microsecond (ntoh ( unsafe_load ( Ptr {Int64} (ptr))) )
391
+ return POSTGRES_EPOCH_DATETIME + Microsecond (value )
412
392
end
413
393
414
394
function pqparse (:: Type{Date} , ptr:: Ptr{UInt8} )
0 commit comments