Skip to content

Commit

Permalink
Revise all datetime pqparse methods to be more consistent.
Browse files Browse the repository at this point in the history
  • Loading branch information
rofinn committed Feb 23, 2023
1 parent 6a5b9f8 commit b82a753
Showing 1 changed file with 30 additions and 25 deletions.
55 changes: 30 additions & 25 deletions src/parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -238,21 +238,31 @@ end
# see https://github.com/invenia/LibPQ.jl/issues/33
_trunc_seconds(str) = replace(str, r"(\.[\d]{3})\d+" => s"\g<1>")

_DEFAULT_TYPE_MAP[:timestamp] = DateTime
const TIMESTAMP_FORMAT = dateformat"y-m-d HH:MM:SS.s" # .s is optional here
function pqparse(::Type{DateTime}, str::AbstractString)
# Utility function for handling "infinity" strings for datetime types to reduce duplication
function _tryparse_datetime_inf(
typ::Type{T}, str, f=typ
)::Union{T, Nothing} where T <: Dates.AbstractDateTime
if str == "infinity"
depwarn_timetype_inf()
return typemax(DateTime)
return f(typemax(DateTime))
elseif str == "-infinity"
depwarn_timetype_inf()
return typemin(DateTime)
return f(typemin(DateTime))
end

# Cut off digits after the third after the decimal point,
# since DateTime in Julia currently handles only milliseconds, see Issue #33
str = replace(str, r"(\.[\d]{3})\d+" => s"\g<1>")
return parse(DateTime, str, TIMESTAMP_FORMAT)
return nothing
end

_DEFAULT_TYPE_MAP[:timestamp] = DateTime
const TIMESTAMP_FORMAT = dateformat"y-m-d HH:MM:SS.s" # .s is optional here
function pqparse(::Type{DateTime}, str::AbstractString)
parsed = _tryparse_datetime_inf(DateTime, str)
isnothing(parsed) || return parsed

parsed = tryparse(DateTime, str, TIMESTAMP_FORMAT)
isnothing(parsed) || return parsed

return parse(DateTime, _trunc_seconds(str), TIMESTAMP_FORMAT)
end

# ISO, YMD
Expand All @@ -265,34 +275,29 @@ const TIMESTAMPTZ_FORMATS = (
)

function pqparse(::Type{ZonedDateTime}, str::AbstractString)
if str == "infinity"
depwarn_timetype_inf()
return ZonedDateTime(typemax(DateTime), tz"UTC")
elseif str == "-infinity"
depwarn_timetype_inf()
return ZonedDateTime(typemin(DateTime), tz"UTC")
end
parsed = _tryparse_datetime_inf(ZonedDateTime, str, Base.Fix2(ZonedDateTime, tz"UTC"))
isnothing(parsed) || return parsed

for fmt in TIMESTAMPTZ_FORMATS[1:(end - 1)]
parsed = tryparse(ZonedDateTime, str, fmt)
parsed !== nothing && return parsed
isnothing(parsed) || return parsed
end

return parse(ZonedDateTime, _trunc_seconds(str), TIMESTAMPTZ_FORMATS[end])
end

function pqparse(::Type{UTCDateTime}, str::AbstractString)
if str == "infinity"
depwarn_timetype_inf()
return UTCDateTime(typemax(DateTime))
elseif str == "-infinity"
depwarn_timetype_inf()
return UTCDateTime(typemin(DateTime))
end
parsed = _tryparse_datetime_inf(UTCDateTime, str)
isnothing(parsed) || return parsed

# Postgres should always give us strings ending with +00 if our timezone is set to UTC
# which is the default
return parse(UTCDateTime, _trunc_seconds(replace(str, "+00" => "")), TIMESTAMP_FORMAT)
str = replace(str, "+00" => "")

parsed = tryparse(UTCDateTime, str, TIMESTAMP_FORMAT)
isnothing(parsed) || return parsed

return parse(UTCDateTime, _trunc_seconds(str), TIMESTAMP_FORMAT)
end

_DEFAULT_TYPE_MAP[:date] = Date
Expand Down

0 comments on commit b82a753

Please sign in to comment.