>From e6db0e40e5464591df204f9d07e66b3d7853c0d7 Mon Sep 17 00:00:00 2001 From: Zefram Date: Wed, 19 Apr 2017 21:50:39 +0100 Subject: [PATCH 1/2] fix SRFI-19's ISO 8601 zone output formats The ISO 8601 timezone formats offered by SRFI-19's date->string function, in the ~2 and ~4 format specifiers, were erroneously in the basic format despite juxtaposition with extended-format date and time. Fix that by switching them to extended format. This incidentally means that the ISO 8601 zone format is no longer implemented as identical to the RFC 822 zone format (~z), so stop documenting them in terms of ~z. The same format specifiers also made too much of an attempt to display zone offsets that are not representable in ISO 8601 format. They would truncate an offset that is not an integral number of minutes, thus producing inaccurate output. The truncation of an offset in the range (-60, 0) yielded a non-conforming "-0000". An offset of 100 hours or more (in either direction) resulted in non-conforming extra digits. In all of these cases, signal as an error that the zone offset is not representable. --- doc/ref/srfi-modules.texi | 4 ++-- module/srfi/srfi-19.scm | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi index ec3bb20..da7850f 100644 --- a/doc/ref/srfi-modules.texi +++ b/doc/ref/srfi-modules.texi @@ -2818,9 +2818,9 @@ with locale decimal point, eg.@: @samp{5.2} @item @nicode{~z} @tab time zone, RFC-822 style @item @nicode{~Z} @tab time zone symbol (not currently implemented) @item @nicode{~1} @tab ISO-8601 date, @samp{~Y-~m-~d} address@hidden @nicode{~2} @tab ISO-8601 time+zone, @samp{~H:~M:~S~z} address@hidden @nicode{~2} @tab ISO-8601 time+zone, @samp{~3} plus zone @item @nicode{~3} @tab ISO-8601 time, @samp{~H:~M:~S} address@hidden @nicode{~4} @tab ISO-8601 date/time+zone, @samp{~Y-~m-~dT~H:~M:~S~z} address@hidden @nicode{~4} @tab ISO-8601 date/time+zone, @samp{~5} plus zone @item @nicode{~5} @tab ISO-8601 date/time, @samp{~Y-~m-~dT~H:~M:~S} @end multitable @end defun diff --git a/module/srfi/srfi-19.scm b/module/srfi/srfi-19.scm index f09ec7a..ed88242 100644 --- a/module/srfi/srfi-19.scm +++ b/module/srfi/srfi-19.scm @@ -152,7 +152,6 @@ (define locale-date-time-format "~a ~b ~d ~H:~M:~S~z ~Y") (define locale-short-date-format "~m/~d/~y") (define locale-time-format "~H:~M:~S") -(define iso-8601-date-time-format "~Y-~m-~dT~H:~M:~S~z") ;;-- Miscellaneous Constants. ;;-- only the tai-epoch-in-jd might need changing if @@ -970,6 +969,21 @@ (display (padding hours #\0 2) port) (display (padding minutes #\0 2) port)))) +(define (iso-8601-tz-print offset port) + (let* ((neg? (negative? offset)) + (all-secs (abs offset)) + (seconds (remainder all-secs 60)) + (all-mins (quotient all-secs 60)) + (minutes (remainder all-mins 60)) + (hours (quotient all-mins 60))) + (if (or (not (= seconds 0)) (> hours 99)) + (time-error 'date-printer 'unrepresentable-zone-offset offset) + (begin + (display (if neg? #\- #\+) port) + (display (padding hours #\0 2) port) + (display #\: port) + (display (padding minutes #\0 2) port))))) + ;; A table of output formatting directives. ;; the first time is the format char. ;; the second is a procedure that takes the date, a padding character @@ -1119,11 +1133,13 @@ (cons #\1 (lambda (date pad-with port) (display (date->string date "~Y-~m-~d") port))) (cons #\2 (lambda (date pad-with port) - (display (date->string date "~H:~M:~S~z") port))) + (display (date->string date "~3") port) + (iso-8601-tz-print (date-zone-offset date) port))) (cons #\3 (lambda (date pad-with port) (display (date->string date "~H:~M:~S") port))) (cons #\4 (lambda (date pad-with port) - (display (date->string date "~Y-~m-~dT~H:~M:~S~z") port))) + (display (date->string date "~5") port) + (iso-8601-tz-print (date-zone-offset date) port))) (cons #\5 (lambda (date pad-with port) (display (date->string date "~Y-~m-~dT~H:~M:~S") port))))) -- 2.1.4