File 1193-stdlib-Let-calendar-system_time_to_rfc3339-keep-frac.patch of Package erlang

From 8ec20295ba052e5666fc77b66c09445233943814 Mon Sep 17 00:00:00 2001
From: Hans Bolinder <hasse@erlang.org>
Date: Mon, 26 Nov 2018 13:12:26 +0100
Subject: [PATCH] stdlib: Let calendar:system_time_to_rfc3339() keep fractions

RFC3339 mentions in paragraph 5.1 that if certain conditions are
fulfilled, then sorting date and time strings results in a
time-ordered sequence. One of the conditions is that the strings must
have the same number of fractional second digits. This commits makes
sure this is indeed the case.
---
 lib/stdlib/doc/src/calendar.xml    |  6 +++-
 lib/stdlib/src/calendar.erl        | 11 +++---
 lib/stdlib/test/calendar_SUITE.erl | 68 ++++++++++++++++++++------------------
 3 files changed, 45 insertions(+), 40 deletions(-)

diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml
index 6b4fa7f98a..5aee635c38 100644
--- a/lib/stdlib/doc/src/calendar.xml
+++ b/lib/stdlib/doc/src/calendar.xml
@@ -403,7 +403,11 @@
 	    default is <c>second</c>. If some other unit is given
 	    (<c>millisecond</c>, <c>microsecond</c>, or
 	    <c>nanosecond</c>), the formatted string includes a
-	    fraction of a second.</p>
+	    fraction of a second. The number of fractional second
+	    digits is three, six, or nine depending on what time unit
+	    is chosen. Notice that trailing zeros are not removed from
+	    the fraction.
+            </p>
 	  </item>
 	</taglist>
         <pre>
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 9a600c1972..bb5d450cd6 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -693,14 +693,11 @@ local_offset(SystemTime, Unit) ->
     UniversalSecs = datetime_to_gregorian_seconds(UniversalTime),
     LocalSecs - UniversalSecs.
 
+fraction_str(1, _Time) ->
+    "";
 fraction_str(Factor, Time) ->
-    case Time rem Factor of
-        0 ->
-            "";
-        Fraction ->
-            FS = io_lib:fwrite(".~*..0B", [log10(Factor), abs(Fraction)]),
-            string:trim(FS, trailing, "0")
-    end.
+    Fraction = Time rem Factor,
+    io_lib:fwrite(".~*..0B", [log10(Factor), abs(Fraction)]).
 
 fraction(second, _) ->
     0;
diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl
index 55118e251c..df62c0921d 100644
--- a/lib/stdlib/test/calendar_SUITE.erl
+++ b/lib/stdlib/test/calendar_SUITE.erl
@@ -183,14 +183,15 @@ rfc3339(Config) when is_list(Config) ->
     D = [{time_designator, $\s}],
     Z = [{offset, "Z"}],
 
-    "1985-04-12T23:20:50.52Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
-    "1985-04-12T23:20:50.52Z" = test_parse("1985-04-12t23:20:50.52z", Ms),
-    "1985-04-12T21:20:50.52Z" =
+    "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
+    "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12t23:20:50.52z", Ms),
+    "1985-04-12T21:20:50.520Z" =
         test_parse("1985-04-12T23:20:50.52+02:00", Ms),
     "1985-04-12T23:20:50Z" = test_parse("1985-04-12T23:20:50.52Z", S),
-    "1985-04-12T23:20:50.52Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
-    "1985-04-12T23:20:50.52Z" = test_parse("1985-04-12t23:20:50.52z", Mys),
-    "1985-04-12 21:20:50.52Z" =
+    "1985-04-12T23:20:50.520Z" = test_parse("1985-04-12T23:20:50.52Z", Ms),
+    "1985-04-12T23:20:50.520000Z" =
+        test_parse("1985-04-12t23:20:50.52z", Mys),
+    "1985-04-12 21:20:50.520000000Z" =
         test_parse("1985-04-12 23:20:50.52+02:00", Ns++D),
     "1985-04-12T23:20:50Z" = test_parse("1985-04-12T23:20:50.52Z"),
     "1996-12-20T00:39:57Z" = test_parse("1996-12-19T16:39:57-08:00"),
@@ -221,17 +222,20 @@ rfc3339(Config) when is_list(Config) ->
     "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60Z"),
     "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.5Z"),
     "1970-01-02T00:00:00Z" = test_parse("1970-01-01T23:59:60.55Z"),
-    "1970-01-02T00:00:00.55Z" = test_parse("1970-01-01T23:59:60.55Z", Ms),
-    "1970-01-02T00:00:00.55Z" = test_parse("1970-01-01T23:59:60.55Z", Mys),
-    "1970-01-02T00:00:00.55Z" = test_parse("1970-01-01T23:59:60.55Z", Ns),
+    "1970-01-02T00:00:00.550Z" = test_parse("1970-01-01T23:59:60.55Z", Ms),
+    "1970-01-02T00:00:00.550000Z" =
+        test_parse("1970-01-01T23:59:60.55Z", Mys),
+    "1970-01-02T00:00:00.550000000Z" =
+        test_parse("1970-01-01T23:59:60.55Z", Ns),
     "1970-01-02T00:00:00.999999Z" =
         test_parse("1970-01-01T23:59:60.999999Z", Mys),
-    "1970-01-02T00:00:01Z" =
+    "1970-01-02T00:00:01.000Z" =
         test_parse("1970-01-01T23:59:60.999999Z", Ms),
     "1970-01-01T00:00:00Z" = test_parse("1970-01-01T00:00:00+00:00"),
     "1970-01-01T00:00:00Z" = test_parse("1970-01-01T00:00:00-00:00"),
     "1969-12-31T00:01:00Z" = test_parse("1970-01-01T00:00:00+23:59"),
-    "1918-11-11T09:00:00Z" = test_parse("1918-11-11T11:00:00+02:00", Mys),
+    "1918-11-11T09:00:00.000000Z" =
+        test_parse("1918-11-11T11:00:00+02:00", Mys),
     "1970-01-01T00:00:00.000001Z" =
         test_parse("1970-01-01T00:00:00.000001Z", Mys),
 
@@ -242,26 +246,26 @@ rfc3339(Config) when is_list(Config) ->
     test_time(erlang:system_time(millisecond), Ms),
     test_time(erlang:system_time(microsecond), Mys++[{offset, "-02:20"}]),
 
-    T = erlang:system_time(second),
-    TS = do_format(T, []),
-    TS = do_format(T * 1000, Ms),
-    TS = do_format(T * 1000 * 1000, Mys),
-    TS = do_format(T * 1000 * 1000 * 1000, Ns),
-
     946720800 = TO = do_parse("2000-01-01 10:00:00Z", []),
     Str = "2000-01-01T10:02:00+00:02",
     Str = do_format(TO, [{offset, 120}]),
-    Str = do_format(TO * 1000, [{offset, 120 * 1000}]++Ms),
-    Str = do_format(TO * 1000 * 1000, [{offset, 120 * 1000 * 1000}]++Mys),
-    Str = do_format(TO * 1000 * 1000 * 1000,
-                    [{offset, 120 * 1000 * 1000 * 1000}]++Ns),
+    "2000-01-01T10:02:00.000+00:02" =
+        do_format(TO * 1000, [{offset, 120 * 1000}]++Ms),
+    "2000-01-01T10:02:00.000000+00:02" =
+        do_format(TO * 1000 * 1000, [{offset, 120 * 1000 * 1000}]++Mys),
+    "2000-01-01T10:02:00.000000000+00:02" =
+        do_format(TO * 1000 * 1000 * 1000,
+                  [{offset, 120 * 1000 * 1000 * 1000}]++Ns),
 
     NStr = "2000-01-01T09:58:00-00:02",
     NStr = do_format(TO, [{offset, -120}]),
-    NStr = do_format(TO * 1000, [{offset, -120 * 1000}]++Ms),
-    NStr = do_format(TO * 1000 * 1000, [{offset, -120 * 1000 * 1000}]++Mys),
-    NStr = do_format(TO * 1000 * 1000 * 1000,
-                     [{offset, -120 * 1000 * 1000 * 1000}]++Ns),
+    "2000-01-01T09:58:00.000-00:02" =
+        do_format(TO * 1000, [{offset, -120 * 1000}]++Ms),
+    "2000-01-01T09:58:00.000000-00:02" =
+        do_format(TO * 1000 * 1000, [{offset, -120 * 1000 * 1000}]++Mys),
+    "2000-01-01T09:58:00.000000000-00:02" =
+        do_format(TO * 1000 * 1000 * 1000,
+                  [{offset, -120 * 1000 * 1000 * 1000}]++Ns),
 
     543210000 = do_parse("1970-01-01T00:00:00.54321Z", Ns),
     54321000 = do_parse("1970-01-01T00:00:00.054321Z", Ns),
@@ -278,18 +282,18 @@ rfc3339(Config) when is_list(Config) ->
     -1613833200000000 = do_parse("1918-11-11T11:00:00+02:00", Mys),
     -1613833200000000 = do_parse("1918-11-11T09:00:00Z", Mys),
 
-    "1970-01-01T00:00:00Z" = do_format_z(0, Mys),
+    "1970-01-01T00:00:00.000000Z" = do_format_z(0, Mys),
     "1970-01-01T00:00:01Z" = do_format_z(1, S),
     "1970-01-01T00:00:00.001Z" = do_format_z(1, Ms),
     "1970-01-01T00:00:00.000001Z" = do_format_z(1, Mys),
     "1970-01-01T00:00:00.000000001Z" = do_format_z(1, Ns),
-    "1970-01-01T00:00:01Z" = do_format_z(1000000, Mys),
-    "1970-01-01T00:00:00.54321Z" = do_format_z(543210, Mys),
+    "1970-01-01T00:00:01.000000Z" = do_format_z(1000000, Mys),
+    "1970-01-01T00:00:00.543210Z" = do_format_z(543210, Mys),
     "1970-01-01T00:00:00.543Z" = do_format_z(543, Ms),
-    "1970-01-01T00:00:00.54321Z" = do_format_z(543210000, Ns),
-    "1970-01-01T00:00:06.54321Z" = do_format_z(6543210, Mys),
-    "1979-06-21T12:12:12Z" = do_format_z(298815132000000, Mys),
-    "1918-11-11T13:00:00Z" = do_format_z(-1613818800000000, Mys),
+    "1970-01-01T00:00:00.543210000Z" = do_format_z(543210000, Ns),
+    "1970-01-01T00:00:06.543210Z" = do_format_z(6543210, Mys),
+    "1979-06-21T12:12:12.000000Z" = do_format_z(298815132000000, Mys),
+    "1918-11-11T13:00:00.000000Z" = do_format_z(-1613818800000000, Mys),
     ok.
 
 %%
-- 
2.16.4