@@ -238,77 +238,66 @@ end
238238# see https://github.com/invenia/LibPQ.jl/issues/33
239239_trunc_seconds (str) = replace (str, r" (\. [\d ]{3})\d +" => s "\g <1>" )
240240
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
244245 if str == " infinity"
245246 depwarn_timetype_inf ()
246- return typemax (DateTime)
247+ return f ( typemax (DateTime) )
247248 elseif str == " -infinity"
248249 depwarn_timetype_inf ()
249- return typemin (DateTime)
250+ return f ( typemin (DateTime) )
250251 end
251252
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)
256266end
257267
258268# ISO, YMD
259269_DEFAULT_TYPE_MAP[:timestamptz ] = ZonedDateTime
260- const TIMESTAMPTZ_ZDT_FORMATS = (
270+ const TIMESTAMPTZ_FORMATS = (
261271 dateformat " y-m-d HH:MM:SSz" ,
262272 dateformat " y-m-d HH:MM:SS.sz" ,
263273 dateformat " y-m-d HH:MM:SS.ssz" ,
264274 dateformat " y-m-d HH:MM:SS.sssz" ,
265275)
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- )
272276
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
275280
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
281284 end
282285
283- return parse (T , _trunc_seconds (str), formats [end ])
286+ return parse (ZonedDateTime , _trunc_seconds (str), TIMESTAMPTZ_FORMATS [end ])
284287end
285288
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
294292
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" => " " )
297296
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
306299
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)
312301end
313302
314303_DEFAULT_TYPE_MAP[:date ] = Date
@@ -363,7 +352,7 @@ function Base.parse(::Type{ZonedDateTime}, pqv::PQValue{PQ_SYSTEM_TYPES[:int8]})
363352end
364353
365354function Base. parse (:: Type{UTCDateTime} , pqv:: PQValue{PQ_SYSTEM_TYPES[:int8]} )
366- return UTCDateTime (unix2datetime ( parse (Int64 , pqv) ))
355+ return UTCDateTime (parse (DateTime , pqv))
367356end
368357
369358# 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})
387376end
388377
389378function 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))
400380end
401381
402382function pqparse (:: Type{DateTime} , ptr:: Ptr{UInt8} )
@@ -408,7 +388,7 @@ function pqparse(::Type{DateTime}, ptr::Ptr{UInt8})
408388 depwarn_timetype_inf ()
409389 return typemin (DateTime)
410390 end
411- return POSTGRES_EPOCH_DATETIME + Microsecond (ntoh ( unsafe_load ( Ptr {Int64} (ptr))) )
391+ return POSTGRES_EPOCH_DATETIME + Microsecond (value )
412392end
413393
414394function pqparse (:: Type{Date} , ptr:: Ptr{UInt8} )
0 commit comments