From 794dc7ca703ec2ce186997d2b48a90bebc04f9ba Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Wed, 31 Jan 2018 23:13:35 -0800
Subject: [PATCH] Add fractional seconds to data format

* NEWS, zic.8: Mention this.
* zic.c (gethms): Accept and ignore fractional seconds.
Simplify by using just one call to sscanf instead of three.
---
 NEWS  |  6 ++++++
 zic.8 |  7 ++++++-
 zic.c | 21 +++++++++++++--------
 3 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/NEWS b/NEWS
index c455f3c..ed7e7d3 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Unreleased, experimental changes
 
   Briefly:
   Support zi parsers that mishandle negative DST offsets
+  Add fractional seconds to source data format.
 
   Changes to build procedure
 
@@ -34,6 +35,11 @@ Unreleased, experimental changes
 
   Changes to code
 
+    zic now accepts fractional seconds in expressions like 00:19:32.13
+    (the UT offset of the Netherlands from 1835 to 1937).  Although
+    zic currently ignores these fractions, they may be useful to
+    applications requiring more precision in historical timestamps.
+
     The code is a bit more portable to MS-Windows.  (Thanks to Manuela
     Friedrich).
 
diff --git a/zic.8 b/zic.8
index b4eface..f1fc8e2 100644
--- a/zic.8
+++ b/zic.8
@@ -251,10 +251,11 @@ Recognized forms include:
 .nf
 .in +.5i
 .sp
-.ta \w'01:28:13\0\0'u
+.ta \w'00:19:32.13\0\0'u
 2	time in hours
 2:00	time in hours and minutes
 01:28:14	time in hours, minutes, and seconds
+00:19:32.13	time with fractional seconds
 15:00	24-hour format time (for times after noon)
 260:00	260 hours after 00:00
 \*-2:30	2.5 hours before 00:00
@@ -264,6 +265,10 @@ Recognized forms include:
 .sp
 where hour 0 is midnight at the start of the day,
 and hour 24 is midnight at the end of the day.
+Although
+.I zic
+currently ignores any fractional seconds, the fractions may be useful
+to other applications requiring greater precision.
 Any of these forms may be followed by the letter
 .B w
 if the given time is local
diff --git a/zic.c b/zic.c
index 55c83e9..4965a10 100644
--- a/zic.c
+++ b/zic.c
@@ -1196,8 +1196,9 @@ static zic_t
 gethms(char const *string, char const *errstring, bool signable)
 {
 	zic_t	hh;
-	int	mm, ss, sign;
-	char xs;
+	int sign, mm = 0, ss = 0;
+	char hhx, mmx, ssx, xs;
+	bool ok = true;
 
 	if (string == NULL || *string == '\0')
 		return 0;
@@ -1207,12 +1208,16 @@ gethms(char const *string, char const *errstring, bool signable)
 		sign = -1;
 		++string;
 	} else	sign = 1;
-	if (sscanf(string, "%"SCNdZIC"%c", &hh, &xs) == 1)
-		mm = ss = 0;
-	else if (sscanf(string, "%"SCNdZIC":%d%c", &hh, &mm, &xs) == 2)
-		ss = 0;
-	else if (sscanf(string, "%"SCNdZIC":%d:%d%c", &hh, &mm, &ss, &xs)
-		 != 3) {
+	switch (sscanf(string,
+		       "%"SCNdZIC"%c%d%c%d%c%*1d%*[0123456789]%c",
+		       &hh, &hhx, &mm, &mmx, &ss, &ssx, &xs)) {
+	  default: ok = false; break;
+	  case 6: ok &= ssx == '.'; /* fallthrough */
+	  case 5: ok &= mmx == ':'; /* fallthrough */
+	  case 3: ok &= hhx == ':'; /* fallthrough */
+	  case 1: break;
+	}
+	if (!ok) {
 			error("%s", errstring);
 			return 0;
 	}
-- 
2.7.4

