From d90372127b11ccccfdaaf819fe26d2ffd17ef82c Mon Sep 17 00:00:00 2001
From: Jonathan Bernard <jonathan@jdbernard.com>
Date: Sun, 1 Aug 2021 23:14:18 -0500
Subject: [PATCH] Further fix for ISO8601 date parsing.

Recognize versions of timestamps with 'T' as the date/time separator.
For example, compare:

    '2021-08-01 23:14:00-05:00'
    '2021-08-01T23:14:00-05:00'

This commit adds support for the second flavor (and it's variations).
---
 fiber_orm.nimble       |  2 +-
 src/fiber_orm/util.nim | 37 +++++++++++++++++++------------------
 2 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/fiber_orm.nimble b/fiber_orm.nimble
index ab2ca19..3a44d17 100644
--- a/fiber_orm.nimble
+++ b/fiber_orm.nimble
@@ -1,6 +1,6 @@
 # Package
 
-version       = "0.3.2"
+version       = "0.3.3"
 author        = "Jonathan Bernard"
 description   = "Lightweight Postgres ORM for Nim."
 license       = "GPL-3.0"
diff --git a/src/fiber_orm/util.nim b/src/fiber_orm/util.nim
index c563a89..806a851 100644
--- a/src/fiber_orm/util.nim
+++ b/src/fiber_orm/util.nim
@@ -67,37 +67,38 @@ proc parsePGDatetime*(val: string): DateTime =
 
   const PG_TIMESTAMP_FORMATS = [
     "yyyy-MM-dd HH:mm:ss",
+    "yyyy-MM-dd'T'HH:mm:ss",
     "yyyy-MM-dd HH:mm:sszz",
+    "yyyy-MM-dd'T'HH:mm:sszz",
     "yyyy-MM-dd HH:mm:ss'.'fff",
-    "yyyy-MM-dd HH:mm:ss'.'fffzz"
+    "yyyy-MM-dd'T'HH:mm:ss'.'fff",
+    "yyyy-MM-dd HH:mm:ss'.'fffzz",
+    "yyyy-MM-dd'T'HH:mm:ss'.'fffzz",
+    "yyyy-MM-dd HH:mm:ss'.'fffzzz",
+    "yyyy-MM-dd'T'HH:mm:ss'.'fffzzz",
   ]
 
-  let PG_PARTIAL_FORMAT_REGEX = re"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.)(\d{1,3})(\S+)?"
-
-  var errStr = ""
-
-  # Try to parse directly using known format strings.
-  for df in PG_TIMESTAMP_FORMATS:
-    try: return val.parse(df)
-    except: errStr &= "\n\t" & getCurrentExceptionMsg()
+  var correctedVal = val;
 
   # 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 PG_PARTIAL_FORMAT_REGEX = re"(\d{4}-\d{2}-\d{2}( |'T')\d{2}:\d{2}:\d{2}\.)(\d{1,2})(\S+)?"
   let match = val.match(PG_PARTIAL_FORMAT_REGEX)
+
   if match.isSome:
     let c = match.get.captures
-    try:
-      if c.toSeq.len == 2:
-        let corrected = c[0] & alignLeft(c[1], 3, '0')
-        return corrected.parse(PG_TIMESTAMP_FORMATS[2])
-      else:
-        let corrected = c[0] & alignLeft(c[1], 3, '0') & c[2]
-        return corrected.parse(PG_TIMESTAMP_FORMATS[3])
-    except:
-      errStr &= "\n\t" & getCurrentExceptionMsg()
+    if c.toSeq.len == 2: correctedVal = c[0] & alignLeft(c[2], 3, '0')
+    else: correctedVal = c[0] & alignLeft(c[2], 3, '0') & c[3]
+
+  var errStr = ""
+
+  # Try to parse directly using known format strings.
+  for df in PG_TIMESTAMP_FORMATS:
+    try: return correctedVal.parse(df)
+    except: errStr &= "\n\t" & getCurrentExceptionMsg()
 
   raise newException(ValueError, "Cannot parse PG date. Tried:" & errStr)