Subject: Re: bug#26238: core-updates: Fix time zone bug in `date` 8.26

From: Leo Famulari <[email-masked]>
Date: Sun, 26 Mar 2017 16:01:14 -0400

On Sun, Mar 26, 2017 at 04:12:40PM +0200, Ludovic Courtès wrote:
> Leo Famulari <[email-masked]> skribis:
> I think ‘coreutils-final’ doesn’t need the replacement because the
> ‘coreutils’ package that we get on GuixSD or when typing ‘guix package
> -i coreutils’ is not ‘coreutils-final’.

Right.

> ‘-final’ is only used as an implicit input of ‘gnu-build-system’, where
> the ‘date’ bug is arguably not a problem.
> 
> So for ‘coreutils-final’, I’d just do:
> 
>   (replacement #f)
> 
> WDYT?

I adapted the example of diffutils-boot0 in the attached patch.

> For good measure, ‘coreutils-minimal’ should also have:
> 
>   (source (package-source coreutils/fixed))
> 
> so that it gets the fix (nothing depends on ‘coreutils-minimal’, so
> there’s no need for a graft here.)

Ah, thanks for pointing this out.

I've attached a revised patch.
From 466a0ebad18ee5e38f280acf19ab19aadffa2206 Mon Sep 17 00:00:00 2001
From: Leo Famulari <[email-masked]>
Date: Fri, 24 Mar 2017 12:18:21 -0400
Subject: [PATCH] gnu: coreutils: Fix a time-zone bug in date 8.26.

* gnu/packages/base.scm (coreutils)[replacement]: New field.
(coreutils/fixed): New variable.
(coreutils-minimal)[source]: Use the source of coreutils/fixed.
* gnu/packages/commencement.scm (coreutils-final)[replacement]: New field.
* gnu/packages/patches/coreutils-fix-time-zone-conversion.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add it.
---
 gnu/local.mk                                       |   1 +
 gnu/packages/base.scm                              |  13 +++
 gnu/packages/commencement.scm                      |  20 ++--
 .../coreutils-fix-time-zone-conversion.patch       | 114 +++++++++++++++++++++
 4 files changed, 139 insertions(+), 9 deletions(-)
 create mode 100644 gnu/packages/patches/coreutils-fix-time-zone-conversion.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 782bf7479..48af6fc40 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -516,6 +516,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/coda-use-system-libs.patch		\
   %D%/packages/patches/coreutils-cut-huge-range-test.patch	\
   %D%/packages/patches/coreutils-fix-cross-compilation.patch    \
+  %D%/packages/patches/coreutils-fix-time-zone-conversion.patch	\
   %D%/packages/patches/cpio-CVE-2016-2037.patch			\
   %D%/packages/patches/cpufrequtils-fix-aclocal.patch		\
   %D%/packages/patches/cracklib-CVE-2016-6318.patch		\
diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm
index 2a6f6a43e..304566ec6 100644
--- a/gnu/packages/base.scm
+++ b/gnu/packages/base.scm
@@ -284,6 +284,7 @@ used to apply commands with arbitrarily long arguments.")
 (define-public coreutils
   (package
    (name "coreutils")
+   (replacement coreutils/fixed)
    (version "8.26")
    (source (origin
             (method url-fetch)
@@ -361,11 +362,23 @@ functionality beyond that which is outlined in the POSIX standard.")
    (license gpl3+)
    (home-page "http://www.gnu.org/software/coreutils/")))
 
+(define coreutils/fixed
+  (package
+    (inherit coreutils)
+    (source
+      (origin
+        (inherit (package-source coreutils))
+        (patches
+          (append
+            (origin-patches (package-source coreutils))
+            (search-patches "coreutils-fix-time-zone-conversion.patch")))))))
+
 (define-public coreutils-minimal
   ;; Coreutils without its optional dependencies.
   (package
     (inherit coreutils)
     (name "coreutils-minimal")
+    (source (package-source coreutils/fixed))
     (outputs '("out"))
     (inputs '())))
 
diff --git a/gnu/packages/commencement.scm b/gnu/packages/commencement.scm
index 675852fb5..fce75b503 100644
--- a/gnu/packages/commencement.scm
+++ b/gnu/packages/commencement.scm
@@ -868,15 +868,17 @@ exec ~a/bin/~a-~a -B~a/lib -Wl,-dynamic-linker -Wl,~a/~a \"$@\"~%"
   ;; The final Coreutils.  Treat them specially because some packages, such as
   ;; Findutils, keep a reference to the Coreutils they were built with.
   (package-with-bootstrap-guile
-   (package-with-explicit-inputs coreutils
-                                 %boot5-inputs
-                                 (current-source-location)
-
-                                 ;; Use the final Guile, linked against the
-                                 ;; final libc with working iconv, so that
-                                 ;; 'substitute*' works well when touching
-                                 ;; test files in Gettext.
-                                 #:guile guile-final)))
+    (let ((p (package-with-explicit-inputs coreutils
+                                           %boot5-inputs
+                                           (current-source-location)
+
+                                           ;; Use the final Guile, linked against the
+                                           ;; final libc with working iconv, so that
+                                           ;; 'substitute*' works well when touching
+                                           ;; test files in Gettext.
+                                           #:guile guile-final)))
+      (package (inherit p)
+        (replacement #f)))))
 
 (define grep-final
   ;; The final grep.  Gzip holds a reference to it (via zgrep), so it must be
diff --git a/gnu/packages/patches/coreutils-fix-time-zone-conversion.patch b/gnu/packages/patches/coreutils-fix-time-zone-conversion.patch
new file mode 100644
index 000000000..56a86b3b5
--- /dev/null
+++ b/gnu/packages/patches/coreutils-fix-time-zone-conversion.patch
@@ -0,0 +1,114 @@
+Fixes a bug in `date` that prevents converting between time zones:
+
+https://bugs.debian.org/851934
+
+Patch copied from upstream source repository:
+
+https://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=b14be5085cd1aefd473a000456b21270e6070711
+
+From b14be5085cd1aefd473a000456b21270e6070711 Mon Sep 17 00:00:00 2001
+From: Paul Eggert <[email-masked]>
+Date: Fri, 20 Jan 2017 18:24:02 -0800
+Subject: [PATCH] date: fix TZ= regression
+
+Problem reported by Paul Wise for Debian, in:
+https://bugs.debian.org/851934
+This is fallout from the fix for GNU Bug#23035.
+* src/date.c (batch_convert): New args TZ and TZSTRING.
+All uses changed.
+(batch_convert, main): Adjust to parse_datetime2 API change.
+(main): Allocate time zone object.
+* tests/misc/date-debug.sh: Fix incorrect test case,
+caught by the fix.
+* tests/misc/date.pl: Test the fix.
+---
+ src/date.c               | 14 +++++++++-----
+ tests/misc/date-debug.sh |  4 ++--
+ tests/misc/date.pl       |  6 ++++++
+ 3 files changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/src/date.c b/src/date.c
+index eed09016d..eb7c624e3 100644
+--- a/src/date.c
++++ b/src/date.c
+@@ -286,7 +286,8 @@ Show the local time for 9AM next Friday on the west coast of the US\n\
+    Return true if successful.  */
+ 
+ static bool
+-batch_convert (const char *input_filename, const char *format, timezone_t tz)
++batch_convert (const char *input_filename, const char *format,
++               timezone_t tz, char const *tzstring)
+ {
+   bool ok;
+   FILE *in_stream;
+@@ -320,7 +321,8 @@ batch_convert (const char *input_filename, const char *format, timezone_t tz)
+           break;
+         }
+ 
+-      if (! parse_datetime2 (&when, line, NULL, parse_datetime_flags))
++      if (! parse_datetime2 (&when, line, NULL,
++                             parse_datetime_flags, tz, tzstring))
+         {
+           if (line[line_length - 1] == '\n')
+             line[line_length - 1] = '\0';
+@@ -502,10 +504,11 @@ main (int argc, char **argv)
+         }
+     }
+ 
+-  timezone_t tz = tzalloc (getenv ("TZ"));
++  char const *tzstring = getenv ("TZ");
++  timezone_t tz = tzalloc (tzstring);
+ 
+   if (batch_file != NULL)
+-    ok = batch_convert (batch_file, format, tz);
++    ok = batch_convert (batch_file, format, tz, tzstring);
+   else
+     {
+       bool valid_date = true;
+@@ -545,7 +548,8 @@ main (int argc, char **argv)
+               if (set_datestr)
+                 datestr = set_datestr;
+               valid_date = parse_datetime2 (&when, datestr, NULL,
+-                                            parse_datetime_flags);
++                                            parse_datetime_flags,
++                                            tz, tzstring);
+             }
+         }
+ 
+diff --git a/tests/misc/date-debug.sh b/tests/misc/date-debug.sh
+index 06de8dd37..48f460506 100755
+--- a/tests/misc/date-debug.sh
++++ b/tests/misc/date-debug.sh
+@@ -48,10 +48,10 @@ date:     new date/time = '(Y-M-D) 1990-12-14 00:00:00 TZ=+09:00'
+ date: '(Y-M-D) 1990-12-14 00:00:00 TZ=+09:00' = 661100400 epoch-seconds
+ date: after time adjustment (+0 hours, -90 minutes, +0 seconds, +0 ns),
+ date:     new time = 661095000 epoch-seconds
+-date: output timezone: -06:00 (set from TZ="America/Belize" environment value)
++date: output timezone: +09:00 (set from TZ="Asia/Tokyo" environment value)
+ date: final: 661095000.000000000 (epoch-seconds)
+ date: final: (Y-M-D) 1990-12-13 13:30:00 (UTC0)
+-date: final: (Y-M-D) 1990-12-13 07:30:00 (output timezone TZ=-06:00)
++date: final: (Y-M-D) 1990-12-13 22:30:00 (output timezone TZ=+09:00)
+ Thu Dec 13 07:30:00 CST 1990
+ EOF
+ 
+diff --git a/tests/misc/date.pl b/tests/misc/date.pl
+index 519c2474d..f026909bf 100755
+--- a/tests/misc/date.pl
++++ b/tests/misc/date.pl
+@@ -291,6 +291,12 @@ my @Tests =
+       {ERR => "date: invalid date 'TZ=\"\"\"'\n"},
+       {EXIT => 1},
+      ],
++
++     # https://bugs.debian.org/851934#10
++     ['cross-TZ-mishandled', "-d 'TZ=\"EST5\" 1970-01-01 00:00'",
++      {ENV => 'TZ=PST8'},
++      {OUT => 'Wed Dec 31 21:00:00 PST 1969'},
++     ],
+     );
+ 
+ # Repeat the cross-dst test, using Jan 1, 2005 and every interval from 1..364.
+-- 
+2.12.0
+
-- 
2.12.0