Support ~N in SRFI-19 string->date
authorDaniel Llorens <daniel.llorens@bluewin.ch>
Mon, 10 Dec 2018 10:57:05 +0000 (11:57 +0100)
committerDaniel Llorens <daniel.llorens@bluewin.ch>
Tue, 11 Dec 2018 21:44:34 +0000 (22:44 +0100)
* module/srfi/srfi-19.scm (fractional-integer-reader,
  make-fractional-integer-reader): From reference implementation.
  (reader-directives): Handle #\N, from reference implementation.
* test-suite/tests/srfi-19: Add tests for string->date ~N.
* doc/ref/srfi-modules.texi (string->date): Add line for ~N.

doc/ref/srfi-modules.texi
module/srfi/srfi-19.scm
test-suite/tests/srfi-19.test

index 99967e57410041eeab95d5fa9ddafbcfd0d87134..11fa24d680dfd5099202463e5b61d1aa8e3d95c6 100644 (file)
@@ -2926,6 +2926,11 @@ the date.
 @tab minute
 @tab @nicode{date-minute}
 
+@item @nicode{~N}
+@tab @nicode{char-numeric?}
+@tab nanosecond
+@tab @nicode{date-nanosecond}
+
 @item @nicode{~S}
 @tab @nicode{char-numeric?}
 @tab second
index 46de91a7ecc76e622bdebe07d02dc5347b682134..66939f92c00d69b894c91fa029a21eaeb53027f2 100644 (file)
   (lambda (port)
     (integer-reader upto port)))
 
+;; read an fractional integer upto n characters long on port; upto -> #f if any length
+;;
+;; The return value is normalized to upto decimal places. For example, if upto is 9 and
+;; the string read is "123", the return value is 123000000.
+(define (fractional-integer-reader upto port)
+  (define (accum-int port accum nchars)
+    (let ((ch (peek-char port)))
+      (if (or (eof-object? ch)
+              (not (char-numeric? ch))
+              (and upto (>= nchars  upto)))
+          (* accum (expt 10 (- upto nchars)))
+          (accum-int port (+ (* accum 10) (char->int (read-char port))) (+ nchars 1)))))
+  (accum-int port 0 0))
+
+(define (make-fractional-integer-reader upto)
+  (lambda (port)
+    (fractional-integer-reader upto port)))
+
 ;; read *exactly* n characters and convert to integer; could be padded
 (define (integer-reader-exact n port)
   (let ((padding-ok #t))
 (define read-directives
   (let ((ireader4 (make-integer-reader 4))
         (ireader2 (make-integer-reader 2))
+        (fireader9 (make-fractional-integer-reader 9))
         (eireader2 (make-integer-exact-reader 2))
         (locale-reader-abbr-weekday (make-locale-reader
                                      locale-abbr-weekday->index))
      (list #\M char-numeric? ireader2 (lambda (val object)
                                         (set-date-minute!
                                          object val)))
+     (list #\N char-numeric? fireader9 (lambda (val object)
+                                        (set-date-nanosecond!
+                                          object val)))
      (list #\S char-numeric? ireader2 (lambda (val object)
                                         (set-date-second! object val)))
      (list #\y char-fail eireader2
index 4d79f104356d26c7cacb2955c89280b500db8e5b..256ff74a0eb03127649dc30fdd50c4f88c4a4189 100644 (file)
@@ -176,6 +176,16 @@ incomplete numerical tower implementation.)"
       (equal? "Sun Jun 05 18:33:00+0200 2005"
               (date->string date))))
 
+  (pass-if "string->date understands nanoseconds (1)"
+    (time=? (date->time-utc (string->date "2018-12-10 10:53:24.189"
+                                          "~Y-~m-~d ~H:~M:~S.~N"))
+            (date->time-utc (make-date 189000000 24 53 10 10 12 2018 3600))))
+
+  (pass-if "string->date understands nanoseconds (2)"
+    (time=? (date->time-utc (string->date "2018-12-10 10:53:24.189654321"
+                                          "~Y-~m-~d ~H:~M:~S.~N"))
+            (date->time-utc (make-date 189654321 24 53 10 10 12 2018 3600))))
+
   (pass-if "date->string pads small nanoseconds values correctly"
     (let* ((date (make-date 99999999 5 34 12 26 3 2017 0)))
       (equal? "099999999"