summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMiran <narimiran@disroot.org>2021-03-11 16:32:50 +0100
committerGitHub <noreply@github.com>2021-03-11 16:32:50 +0100
commite922d73dd6b74a0ea9e1588bca945662f0797a9c (patch)
tree49400a718f09064aae897b0867c90d5d5ed76c14
parent76a3b350ce0fa587f8a6c8d95256c428b0386b4e (diff)
downloadNim-e922d73dd6b74a0ea9e1588bca945662f0797a9c.tar.gz
refs #4347, add `ZZZ` and `ZZZZ` patterns for timezone offsets without colons (#17318)
-rw-r--r--changelog.md36
-rw-r--r--lib/pure/times.nim46
-rw-r--r--tests/stdlib/ttimes.nim4
3 files changed, 63 insertions, 23 deletions
diff --git a/changelog.md b/changelog.md
index 05211b116..5b5cdabf1 100644
--- a/changelog.md
+++ b/changelog.md
@@ -83,13 +83,19 @@
 - `writeStackTrace` is available in JS backend now.
 
 - Added `decodeQuery` to `std/uri`.
+
 - `strscans.scanf` now supports parsing single characters.
-- `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`.
+
+- `strscans.scanTuple` added which uses `strscans.scanf` internally,
+  returning a tuple which can be unpacked for easier usage of `scanf`.
 
 - Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`,
   if the iterable yields a built-in settable type.
+
 - Added `setutils.fullSet` which returns a full built-in `set` for a valid type.
+
 - Added `setutils.complement` which returns the complement of a built-in `set`.
+
 - Added `setutils.[]=`.
 
 - Added `math.isNaN`.
@@ -100,20 +106,24 @@
 - Added `jsbigints` module, arbitrary precision integers for JavaScript target.
 
 - Added `math.copySign`.
+
 - Added new operations for singly- and doubly linked lists: `lists.toSinglyLinkedList`
   and `lists.toDoublyLinkedList` convert from `openArray`s; `lists.copy` implements
   shallow copying; `lists.add` concatenates two lists - an O(1) variation that consumes
   its argument, `addMoved`, is also supplied.
 
 - Added `euclDiv` and `euclMod` to `math`.
+
 - Added `httpcore.is1xx` and missing HTTP codes.
+
 - Added `jsconsole.jsAssert` for JavaScript target.
 
 - Added `posix_utils.osReleaseFile` to get system identification from `os-release` file on Linux and the BSDs.
   https://www.freedesktop.org/software/systemd/man/os-release.html
 
 - `math.round` now is rounded "away from zero" in JS backend which is consistent
-with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
+  with other backends. See #9125. Use `-d:nimLegacyJsRound` for previous behavior.
+
 - Added `socketstream` module that wraps sockets in the stream interface
 
 - Changed the behavior of `uri.decodeQuery` when there are unencoded `=`
@@ -127,8 +137,8 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
 
 - Added `math.signbit`.
 
-
 - Removed the optional `longestMatch` parameter of the `critbits._WithPrefix` iterators (it never worked reliably)
+
 - In `lists`: renamed `append` to `add` and retained `append` as an alias;
   added `prepend` and `prependMoved` analogously to `add` and `addMoved`;
   added `remove` for `SinglyLinkedList`s.
@@ -136,17 +146,20 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
 - Deprecated `any`. See https://github.com/nim-lang/RFCs/issues/281
 
 - Added `std/sysrand` module to get random numbers from a secure source
-provided by the operating system.
+  provided by the operating system.
 
 - Added optional `options` argument to `copyFile`, `copyFileToDir`, and
   `copyFileWithPermissions`. By default, on non-Windows OSes, symlinks are
   followed (copy files symlinks point to); on Windows, `options` argument is
   ignored and symlinks are skipped.
+
 - On non-Windows OSes, `copyDir` and `copyDirWithPermissions` copy symlinks as
   symlinks (instead of skipping them as it was before); on Windows symlinks are
   skipped.
+
 - On non-Windows OSes, `moveFile` and `moveDir` move symlinks as symlinks
   (instead of skipping them sometimes as it was before).
+
 - Added optional `followSymlinks` argument to `setFilePermissions`.
 
 - Added `os.isAdmin` to tell whether the caller's process is a member of the
@@ -196,10 +209,12 @@ provided by the operating system.
 
 - `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
   and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
+
 - Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target.
+
 - Added `std/jsheaders` module [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) wrapper for JavaScript target.
-- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target.
 
+- Added `std/jsformdata` module [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) wrapper for JavaScript target.
 
 - `system.addEscapedChar` now renders `\r` as `\r` instead of `\c`, to be compatible
   with most other languages.
@@ -208,7 +223,12 @@ provided by the operating system.
 
 - Added `jscore.debugger` to [call any available debugging functionality, such as breakpoints.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger)
 
-- Added `htmlgen.portal` for [making "SPA style" pages using HTML only.](https://web.dev/hands-on-portals)
+- Added `htmlgen.portal` for [making "SPA style" pages using HTML only](https://web.dev/hands-on-portals).
+
+- Added `ZZZ` and `ZZZZ` patterns to `times.nim` `DateTime` parsing, to match time
+  zone offsets without colons, e.g. `UTC+7 -> +0700`.
+
+
 
 
 ## Language changes
@@ -229,6 +249,8 @@ provided by the operating system.
 
 - `typedesc[Foo]` now renders as such instead of `type Foo` in compiler messages.
 
+
+
 ## Compiler changes
 
 - Added `--declaredlocs` to show symbol declaration location in messages.
@@ -266,6 +288,8 @@ provided by the operating system.
 
 - Added `unsafeIsolate` and `extract` to `std/isolation`.
 
+
+
 ## Tool changes
 
 - The rst parser now supports markdown table syntax.
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 523cda08f..e4d31867b 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -110,8 +110,12 @@
                                                                                                   | `UTC-5 -> -05`
   `zzz`        Same as above but with `:mm` where *mm* represents minutes.                        | `UTC+7 -> +07:00`
                                                                                                   | `UTC-5 -> -05:00`
+  `ZZZ`        Same as above but with `mm` where *mm* represents minutes.                         | `UTC+7 -> +0700`
+                                                                                                  | `UTC-5 -> -0500`
   `zzzz`       Same as above but with `:ss` where *ss* represents seconds.                        | `UTC+7 -> +07:00:00`
                                                                                                   | `UTC-5 -> -05:00:00`
+  `ZZZZ`       Same as above but with `ss` where *ss* represents seconds.                         | `UTC+7 -> +070000`
+                                                                                                  | `UTC-5 -> -050000`
   `g`          Era: AD or BC                                                                      | `300 AD -> AD`
                                                                                                   | `300 BC -> BC`
   `fff`        Milliseconds display                                                               | `1000000 nanoseconds -> 1`
@@ -1469,6 +1473,7 @@ type
     uuuu
     UUUU
     z, zz, zzz, zzzz
+    ZZZ, ZZZZ
     g
 
     # This is a special value used to mark literal format values.
@@ -1621,6 +1626,8 @@ proc stringToPattern(str: string): FormatPattern =
   of "zz": result = zz
   of "zzz": result = zzz
   of "zzzz": result = zzzz
+  of "ZZZ": result = ZZZ
+  of "ZZZZ": result = ZZZZ
   of "g": result = g
   else: raise newException(TimeFormatParseError,
                            "'" & str & "' is not a valid pattern")
@@ -1727,7 +1734,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string,
       result.add '+' & $year
   of UUUU:
     result.add $dt.year
-  of z, zz, zzz, zzzz:
+  of z, zz, zzz, zzzz, ZZZ, ZZZZ:
     if dt.timezone != nil and dt.timezone.name == "Etc/UTC":
       result.add 'Z'
     else:
@@ -1738,16 +1745,18 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string,
         result.add $(absOffset div 3600)
       of zz:
         result.add (absOffset div 3600).intToStr(2)
-      of zzz:
+      of zzz, ZZZ:
         let h = (absOffset div 3600).intToStr(2)
         let m = ((absOffset div 60) mod 60).intToStr(2)
-        result.add h & ":" & m
-      of zzzz:
+        let sep = if pattern == zzz: ":" else: ""
+        result.add h & sep & m
+      of zzzz, ZZZZ:
         let absOffset = abs(dt.utcOffset)
         let h = (absOffset div 3600).intToStr(2)
         let m = ((absOffset div 60) mod 60).intToStr(2)
         let s = (absOffset mod 60).intToStr(2)
-        result.add h & ":" & m & ":" & s
+        let sep = if pattern == zzzz: ":" else: ""
+        result.add h & sep & m & sep & s
       else: assert false
   of g:
     result.add if dt.year < 1: "BC" else: "AD"
@@ -1881,7 +1890,7 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
     parsed.year = some(year)
   of UUUU:
     parsed.year = some(takeInt(1..high(int), allowSign = true))
-  of z, zz, zzz, zzzz:
+  of z, zz, zzz, zzzz, ZZZ, ZZZZ:
     case input[i]
     of '+', '-':
       let sign = if input[i] == '-': 1 else: -1
@@ -1892,21 +1901,24 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
         offset = takeInt(1..2) * 3600
       of zz:
         offset = takeInt(2..2) * 3600
-      of zzz:
+      of zzz, ZZZ:
         offset.inc takeInt(2..2) * 3600
-        if input[i] != ':':
-          return false
-        i.inc
+        if pattern == zzz:
+          if input[i] != ':':
+            return false
+          i.inc
         offset.inc takeInt(2..2) * 60
-      of zzzz:
+      of zzzz, ZZZZ:
         offset.inc takeInt(2..2) * 3600
-        if input[i] != ':':
-          return false
-        i.inc
+        if pattern == zzzz:
+          if input[i] != ':':
+            return false
+          i.inc
         offset.inc takeInt(2..2) * 60
-        if input[i] != ':':
-          return false
-        i.inc
+        if pattern == zzzz:
+          if input[i] != ':':
+            return false
+          i.inc
         offset.inc takeInt(2..2)
       else: assert false
       parsed.utcOffset = some(offset * sign)
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index dc9468def..66157b91c 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -84,6 +84,10 @@ template runTimezoneTests() =
       "2001-01-12T08:04:05Z", 11)
   parseTest("2001-01-12T15:04:05 +07:30:59", "yyyy-MM-dd'T'HH:mm:ss zzzz",
       "2001-01-12T07:33:06Z", 11)
+  parseTest("2001-01-12T15:04:05 +0700", "yyyy-MM-dd'T'HH:mm:ss ZZZ",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +073059", "yyyy-MM-dd'T'HH:mm:ss ZZZZ",
+      "2001-01-12T07:33:06Z", 11)
   # Kitchen     = "3:04PM"
   parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00")