Fix support for PostgreSQL timestamp fields.
PostgreSQL uses a format similar to IS8601 but allows values expressed with tenths or hundreths of seconds rather than just milliseconds. `2020-01-01 12:34:98.3+00` as opposed to `2020-01-01 12:34:98.300+00`, for example. The `times` module in the Nim stdlib supports only milliseconds with exactly three digits. To bridge this gap we detect the two unsupported cases and pad the fractional seconds out to millisecond precision.
This commit is contained in:
parent
61e06842af
commit
1f57e0dccc
@ -1,14 +1,16 @@
|
|||||||
import json, macros, options, sequtils, strutils, times, timeutils, unicode,
|
import json, macros, options, sequtils, strutils, times, timeutils, unicode,
|
||||||
uuids
|
uuids
|
||||||
|
|
||||||
|
import nre except toSeq
|
||||||
|
|
||||||
const UNDERSCORE_RUNE = "_".toRunes[0]
|
const UNDERSCORE_RUNE = "_".toRunes[0]
|
||||||
const PG_TIMESTAMP_FORMATS = [
|
const PG_TIMESTAMP_FORMATS = [
|
||||||
"yyyy-MM-dd HH:mm:sszz",
|
"yyyy-MM-dd HH:mm:sszz",
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fzz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'ffzz",
|
|
||||||
"yyyy-MM-dd HH:mm:ss'.'fffzz"
|
"yyyy-MM-dd HH:mm:ss'.'fffzz"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
var PG_PARTIAL_FORMAT_REGEX = re"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.)(\d{1,3})(\S+)?"
|
||||||
|
|
||||||
type
|
type
|
||||||
MutateClauses* = object
|
MutateClauses* = object
|
||||||
columns*: seq[string]
|
columns*: seq[string]
|
||||||
@ -69,9 +71,27 @@ type DbArrayParseState = enum
|
|||||||
|
|
||||||
proc parsePGDatetime*(val: string): DateTime =
|
proc parsePGDatetime*(val: string): DateTime =
|
||||||
var errStr = ""
|
var errStr = ""
|
||||||
|
|
||||||
|
# Try to parse directly using known format strings.
|
||||||
for df in PG_TIMESTAMP_FORMATS:
|
for df in PG_TIMESTAMP_FORMATS:
|
||||||
try: return val.parse(df)
|
try: return val.parse(df)
|
||||||
except: errStr &= "\n" & getCurrentExceptionMsg()
|
except: errStr &= "\n\t" & getCurrentExceptionMsg()
|
||||||
|
|
||||||
|
# PostgreSQL will truncate any trailing 0's in the millisecond value leading
|
||||||
|
# to values like `2020-01-01 16:42.3+00`. This cannot currently be parsed by
|
||||||
|
# the standard times format as it expects exactly three digits for
|
||||||
|
# millisecond values. So we have to detect this and pad out the millisecond
|
||||||
|
# value to 3 digits.
|
||||||
|
let match = val.match(PG_PARTIAL_FORMAT_REGEX)
|
||||||
|
if match.isSome:
|
||||||
|
let c = match.get.captures
|
||||||
|
try:
|
||||||
|
let corrected = c[0] & alignLeft(c[1], 3, '0') & c[2]
|
||||||
|
return corrected.parse(PG_TIMESTAMP_FORMATS[1])
|
||||||
|
except:
|
||||||
|
errStr &= "\n\t" & PG_TIMESTAMP_FORMATS[1] &
|
||||||
|
" after padding out milliseconds to full 3-digits"
|
||||||
|
|
||||||
raise newException(ValueError, "Cannot parse PG date. Tried:" & errStr)
|
raise newException(ValueError, "Cannot parse PG date. Tried:" & errStr)
|
||||||
|
|
||||||
proc parseDbArray*(val: string): seq[string] =
|
proc parseDbArray*(val: string): seq[string] =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user