Skip to content

Commit 572b7ff

Browse files
authored
Merge pull request #591 from JuliaRobotics/3Q20/fixing_timestamps_regex
Robust ZonedTimestamp fixer
2 parents a245c2e + b26bf8e commit 572b7ff

File tree

1 file changed

+35
-43
lines changed

1 file changed

+35
-43
lines changed

src/services/Serialization.jl

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,62 +10,56 @@ 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+
# Additional check+fix for the ultraweird "2020-08-12T12:00Z"
25+
ts = replace(stringTimestamp, r"T(\d\d):(\d\d)(Z|z|\+|-)" => s"T\1:\2:00.000\3")
26+
27+
# This is finding :59Z or :59.82-05:00 and fixing it to always have 3 subsecond digits.
28+
# Temporary fix until TimeZones.jl gets an upstream fix.
29+
return replace(ts, r":\d\d(\.\d+)?(Z|z|\+|-)" => _fixSubseconds)
30+
end
31+
32+
# Corrects any `::ZonedDateTime` fields of T in corresponding `interm::Dict` as `dateformat"yyyy-mm-ddTHH:MM:SS.ssszzz"`
33+
function standardizeZDTStrings!(T, interm::Dict)
34+
for (name, typ) in zip(fieldnames(T), T.types)
35+
if typ <: ZonedDateTime
36+
namestr = string(name)
37+
interm[namestr] = getStandardZDTString(interm[namestr])
38+
end
39+
end
40+
nothing
41+
end
42+
1343
##==============================================================================
1444
## Variable Packing and unpacking
1545
##==============================================================================
1646
function packVariable(dfg::G, v::DFGVariable)::Dict{String, Any} where G <: AbstractDFG
1747
props = Dict{String, Any}()
1848
props["label"] = string(v.label)
19-
props["timestamp"] = Dates.format(v.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")#string(v.timestamp)
49+
props["timestamp"] = Dates.format(v.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")
2050
props["nstime"] = string(v.nstime.value)
2151
props["tags"] = JSON2.write(v.tags)
2252
props["ppeDict"] = JSON2.write(v.ppeDict)
2353
props["solverDataDict"] = JSON2.write(Dict(keys(v.solverDataDict) .=> map(vnd -> packVariableNodeData(dfg, vnd), values(v.solverDataDict))))
2454
props["smallData"] = JSON2.write(v.smallData)
2555
props["solvable"] = v.solvable
2656
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))))
2957
props["dataEntry"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> JSON.json(bde), values(v.dataDict))))
3058

3159
props["dataEntryType"] = JSON2.write(Dict(keys(v.dataDict) .=> map(bde -> typeof(bde), values(v.dataDict))))
3260
return props
3361
end
3462

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-
6963
function unpackVariable(dfg::G,
7064
packedProps::Dict{String, Any};
7165
unpackPPEs::Bool=true,
@@ -74,7 +68,7 @@ function unpackVariable(dfg::G,
7468
@debug "Unpacking variable:\r\n$packedProps"
7569
label = Symbol(packedProps["label"])
7670
# 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")
71+
packedProps["timestamp"] = getStandardZDTString(packedProps["timestamp"])
7872
# Parse it
7973
timestamp = ZonedDateTime(packedProps["timestamp"])
8074
nstime = Nanosecond(get(packedProps, "nstime", 0))
@@ -122,11 +116,9 @@ function unpackVariable(dfg::G,
122116
end
123117

124118
for (k,bdeInter) in dataIntermed
125-
# @debug "label=$label"
126-
# @debug "bdeInter=$bdeInter"
127119
interm = JSON.parse(bdeInter)
128120
objType = getfield(DistributedFactorGraphs, dataElemTypes[k])
129-
standardizeZDTString!(objType, interm)
121+
standardizeZDTStrings!(objType, interm)
130122
fullVal = Unmarshal.unmarshal(objType, interm)
131123
variable.dataDict[k] = fullVal
132124
end
@@ -183,7 +175,7 @@ function packFactor(dfg::G, f::DFGFactor)::Dict{String, Any} where G <: Abstract
183175
# Construct the properties to save
184176
props = Dict{String, Any}()
185177
props["label"] = string(f.label)
186-
props["timestamp"] = Dates.format(f.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")#string(f.timestamp)
178+
props["timestamp"] = Dates.format(f.timestamp, "yyyy-mm-ddTHH:MM:SS.ssszzz")
187179
props["nstime"] = string(f.nstime.value)
188180
props["tags"] = JSON2.write(f.tags)
189181
# Pack the node data
@@ -221,7 +213,7 @@ end
221213
function unpackFactor(dfg::G, packedProps::Dict{String, Any})::DFGFactor where G <: AbstractDFG
222214
label = packedProps["label"]
223215
# Make sure that the timestamp is correctly formatted with subseconds
224-
packedProps["timestamp"] = replace(packedProps["timestamp"], r":(\d)(\d)(Z|z|\+|-)" => s":\1\2.000\3")
216+
packedProps["timestamp"] = getStandardZDTString(packedProps["timestamp"])
225217
# Parse it
226218
timestamp = ZonedDateTime(packedProps["timestamp"])
227219
nstime = Nanosecond(get(packedProps, "nstime", 0))

0 commit comments

Comments
 (0)