Skip to content

Commit 1cca915

Browse files
committed
Robust ZonedTimestamp fixer
1 parent c0bc0c7 commit 1cca915

File tree

1 file changed

+32
-43
lines changed

1 file changed

+32
-43
lines changed

src/services/Serialization.jl

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,53 @@ import JSON.Serializations: CommonSerialization, StandardSerialization
1010
JSON.show_json(io::JSONContext, serialization::CommonSerialization, uuid::UUID) = print(io.io, "\"$uuid\"")
1111

1212

13+
## Utility functions for ZonedDateTime
14+
15+
# Regex parser that converts clauses like ":59.82-" to well formatted ":59.820-"
16+
function _fixSubseconds(a)
17+
length(a) == 4 && return a[1:3]*".000"*a[4]
18+
frac = a[5:length(a)-1]
19+
frac = length(frac) > 3 ? frac[1:3] : frac*'0'^(3-length(frac))
20+
return a[1:4]*frac*a[length(a)]
21+
end
22+
23+
function getStandardZDTString(stringTimestamp::String)
24+
# This is finding :59Z or :59.82-05:00 and fixing it to always have 3 subsecond digits.
25+
# Temporary fix until TimeZones.jl gets an upstream fix.
26+
return replace(stringTimestamp, r":\d\d(\.\d+)?(Z|z|\+|-)" => _fixSubseconds)
27+
end
28+
29+
# Corrects any `::ZonedDateTime` fields of T in corresponding `interm::Dict` as `dateformat"yyyy-mm-ddTHH:MM:SS.ssszzz"`
30+
function standardizeZDTStrings!(T, interm::Dict)
31+
for (name, typ) in zip(fieldnames(T), T.types)
32+
if typ <: ZonedDateTime
33+
namestr = string(name)
34+
interm[namestr] = getStandardZDTString(interm[namestr])
35+
end
36+
end
37+
nothing
38+
end
39+
1340
##==============================================================================
1441
## Variable Packing and unpacking
1542
##==============================================================================
1643
function packVariable(dfg::G, v::DFGVariable)::Dict{String, Any} where G <: AbstractDFG
1744
props = Dict{String, Any}()
1845
props["label"] = string(v.label)
19-
props["timestamp"] = Dates.format(v.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")#string(v.timestamp)
46+
props["timestamp"] = Dates.format(v.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")
2047
props["nstime"] = string(v.nstime.value)
2148
props["tags"] = JSON2.write(v.tags)
2249
props["ppeDict"] = JSON2.write(v.ppeDict)
2350
props["solverDataDict"] = JSON2.write(Dict(keys(v.solverDataDict) .=> map(vnd -> packVariableNodeData(dfg, vnd), values(v.solverDataDict))))
2451
props["smallData"] = JSON2.write(v.smallData)
2552
props["solvable"] = v.solvable
2653
props["softtype"] = string(typeof(getSofttype(v)))
27-
# props["bigData"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> JSON2.write(bde), values(v.dataDict))))
28-
# props["bigDataElemType"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> typeof(bde), values(v.dataDict))))
2954
props["dataEntry"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> JSON.json(bde), values(v.dataDict))))
3055

3156
props["dataEntryType"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> typeof(bde), values(v.dataDict))))
3257
return props
3358
end
3459

35-
# Corrects any `::ZonedDateTime` fields of T in corresponding `interm::Dict` as `dateformat"yyyy-mm-ddTHH:MM:SS.ssszzz"`
36-
function standardizeZDTString!(T, interm::Dict)
37-
@debug "About to look through types of" T
38-
for (name, typ) in zip(fieldnames(T), T.types)
39-
# @debug "name=$name"
40-
# @debug "typ=$typ"
41-
if typ <: ZonedDateTime
42-
# Make sure that the timestamp is correctly formatted with subseconds
43-
namestr = string(name)
44-
@debug "must ensure SS.ssszzz on $name :: $typ -- $(interm[namestr])"
45-
# # FIXME copy #588, but doesnt work: https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/582#issuecomment-671884668
46-
# # E.g.: interm[namestr] = replace(interm[namestr], r":(\d)(\d)(Z|z|\+|-)" => s":\1\2.000\3") = "2020-08-11T04:05:59.82-04:00"
47-
# @show interm[namestr] = replace(interm[namestr], r":(\d)(\d)(Z|z|\+|-)" => s":\1\2.000\3")
48-
# @debug "after SS.ssszzz -- $(interm[namestr])"
49-
## DROP piece below once this cleaner copy #588 is working
50-
supersec, subsec = split(interm[namestr], '.')
51-
sss, zzz = split(subsec, '-')
52-
# @debug "split time elements are $sss-$zzz"
53-
# make sure milliseconds portion is precisely 3 characters long
54-
if length(sss) < 3
55-
# pad with zeros at the end
56-
while length(sss) < 3
57-
sss *= "0"
58-
end
59-
newtimessszzz = supersec*"."*sss*"-"*zzz
60-
@debug "new time string: $newtimessszzz"
61-
# reassembled ZonedDateTime is put back in the dict
62-
interm[namestr] = newtimessszzz
63-
end
64-
end
65-
end
66-
nothing
67-
end
68-
6960
function unpackVariable(dfg::G,
7061
packedProps::Dict{String, Any};
7162
unpackPPEs::Bool=true,
@@ -74,7 +65,7 @@ function unpackVariable(dfg::G,
7465
@debug "Unpacking variable:\r\n$packedProps"
7566
label = Symbol(packedProps["label"])
7667
# Make sure that the timestamp is correctly formatted with subseconds
77-
packedProps["timestamp"] = replace(packedProps["timestamp"], r":(\d)(\d)(Z|z|\+|-)" => s":\1\2.000\3")
68+
packedProps["timestamp"] = getStandardZDTString(packedProps["timestamp"])
7869
# Parse it
7970
timestamp = ZonedDateTime(packedProps["timestamp"])
8071
nstime = Nanosecond(get(packedProps, "nstime", 0))
@@ -119,11 +110,9 @@ function unpackVariable(dfg::G,
119110
end
120111

121112
for (k,bdeInter) in dataIntermed
122-
# @debug "label=$label"
123-
# @debug "bdeInter=$bdeInter"
124113
interm = JSON.parse(bdeInter)
125114
objType = getfield(DistributedFactorGraphs, dataElemTypes[k])
126-
standardizeZDTString!(objType, interm)
115+
standardizeZDTStrings!(objType, interm)
127116
fullVal = Unmarshal.unmarshal(objType, interm)
128117
variable.dataDict[k] = fullVal
129118
end
@@ -180,7 +169,7 @@ function packFactor(dfg::G, f::DFGFactor)::Dict{String, Any} where G <: Abstract
180169
# Construct the properties to save
181170
props = Dict{String, Any}()
182171
props["label"] = string(f.label)
183-
props["timestamp"] = Dates.format(f.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")#string(f.timestamp)
172+
props["timestamp"] = Dates.format(f.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")
184173
props["nstime"] = string(f.nstime.value)
185174
props["tags"] = JSON2.write(f.tags)
186175
# Pack the node data
@@ -218,7 +207,7 @@ end
218207
function unpackFactor(dfg::G, packedProps::Dict{String, Any})::DFGFactor where G <: AbstractDFG
219208
label = packedProps["label"]
220209
# Make sure that the timestamp is correctly formatted with subseconds
221-
packedProps["timestamp"] = replace(packedProps["timestamp"], r":(\d)(\d)(Z|z|\+|-)" => s":\1\2.000\3")
210+
packedProps["timestamp"] = getStandardZDTString(packedProps["timestamp"])
222211
# Parse it
223212
timestamp = ZonedDateTime(packedProps["timestamp"])
224213
nstime = Nanosecond(get(packedProps, "nstime", 0))

0 commit comments

Comments
 (0)