Subject: bug#21904: date->string duff ISO 8601 format for non-4-digit years

From: Zefram <[email-masked]>
Date: Thu, 20 Apr 2017 01:04:37 +0100

A patch to fix this is attached.  The ISO 8601 date formats were
implemented by using the ~Y formatter for the year portion, but SRFI-19
doesn't require ~Y to follow ISO 8601, so this raises the question of
whether ~Y should.  It could be fixed by changing ~Y to conform to
ISO 8601, retaining the existing factoring of the formatters.  Or a
separate internal formatting function could be instituted to do ISO
8601 year formatting, with ~1 et al using that and ~Y left unchanged.
I chose the former strategy, partly because the funny non-linear year
number doesn't seem a useful thing to support in date->string at all,
but more strongly because it's useful to have access to ISO 8601 year
formatting on its own.  There isn't any other format specifier for that
job; it looks like SRFI-19 imagines that ~Y will fill that need.

-zefram
>From 43dfb5fabc9debb80f87b17d82a1adde356e547c Mon Sep 17 00:00:00 2001
From: Zefram <[email-masked]>
Date: Thu, 20 Apr 2017 00:42:54 +0100
Subject: [PATCH 1/2] fix SRFI-19's ISO 8601 year syntax

The ISO 8601 date formats offered by SRFI-19's date->string function
were emitting incorrect syntax for most years.  At least four digits
of year must be given, but it wasn't padding shorter numbers.  And any
number with more than four digits requires a leading sign, but this was
being omitted for positive numbers.  These problems are now fixed.

The ISO 8601 date formats were formerly implemented in terms of the ~Y
format, which was not specified to be an ISO 8601 format.  The fix is
achieved by altering ~Y to behave in the ISO 8601 manner, and ~Y is
now documented to conform to ISO 8601.  Doing it this way means that
ISO 8601 year numbering is available in isolation, which is a useful
facility not otherwise available.
---
 doc/ref/srfi-modules.texi | 1 +
 module/srfi/srfi-19.scm   | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index da7850f..8a5f1a0 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -2815,6 +2815,7 @@ with locale decimal point, eg.@: @samp{5.2}
 
 @item @nicode{~y} @tab year, two digits, @samp{00} to @samp{99}
 @item @nicode{~Y} @tab year, full, eg.@: @samp{2003}
+(in ISO 8601 format, though SRFI-19 doesn't specify so)
 @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}
diff --git a/module/srfi/srfi-19.scm b/module/srfi/srfi-19.scm
index 4b8445f..d4308bb 100644
--- a/module/srfi/srfi-19.scm
+++ b/module/srfi/srfi-19.scm
@@ -1128,7 +1128,10 @@
                                       2)
                         port)))
    (cons #\Y (lambda (date pad-with port)
-               (display (date-year date) port)))
+	       (let ((y (date-year date)))
+		 (cond ((negative? y) (display #\- port))
+		       ((>= y 10000) (display #\+ port)))
+		 (display (padding (abs y) #\0 4) port))))
    (cons #\z (lambda (date pad-with port)
                (rfc-822-tz-print (date-zone-offset date) port)))
    (cons #\Z (lambda (date pad-with port)
-- 
2.1.4