* NEWS, zic.8: Mention this. * zic.c (gethms): Round to even instead of discarding fractional seconds. --- NEWS | 5 +++-- zic.8 | 4 +++- zic.c | 18 ++++++++++++++---- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index f00b29f..adc9814 100644 --- a/NEWS +++ b/NEWS @@ -45,8 +45,9 @@ Unreleased, experimental changes 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. + zic currently rounds these fractions to the nearest integer + (breaking ties to the even integer), the fractions 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 f1fc8e2..28e4bd6 100644 --- a/zic.8 +++ b/zic.8 @@ -267,8 +267,10 @@ 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 +currently rounds fractional seconds to the nearest integer +(breaking ties to the even integer), the fractions may be useful to other applications requiring greater precision. +The source format does not specify any maximum 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 4965a10..6ad31f9 100644 --- a/zic.c +++ b/zic.c @@ -1197,7 +1197,8 @@ gethms(char const *string, char const *errstring, bool signable) { zic_t hh; int sign, mm = 0, ss = 0; - char hhx, mmx, ssx, xs; + char hhx, mmx, ssx, xr = '0', xs; + int tenths = 0; bool ok = true; if (string == NULL || *string == '\0') @@ -1209,10 +1210,18 @@ gethms(char const *string, char const *errstring, bool signable) ++string; } else sign = 1; switch (sscanf(string, - "%"SCNdZIC"%c%d%c%d%c%*1d%*[0123456789]%c", - &hh, &hhx, &mm, &mmx, &ss, &ssx, &xs)) { + "%"SCNdZIC"%c%d%c%d%c%1d%*[0]%c%*[0123456789]%c", + &hh, &hhx, &mm, &mmx, &ss, &ssx, &tenths, &xr, &xs)) { default: ok = false; break; - case 6: ok &= ssx == '.'; /* fallthrough */ + case 8: + ok = '0' <= xr && xr <= '9'; + /* fallthrough */ + case 7: + ok &= ssx == '.'; + if (ok && noise) + warning(_("fractional seconds rejected by" + " pre-2018 versions of zic")); + /* fallthrough */ case 5: ok &= mmx == ':'; /* fallthrough */ case 3: ok &= hhx == ':'; /* fallthrough */ case 1: break; @@ -1231,6 +1240,7 @@ gethms(char const *string, char const *errstring, bool signable) error(_("time overflow")); return 0; } + ss += 5 + ((ss ^ 1) & (xr == '0')) <= tenths; /* Round to even. */ if (noise && (hh > HOURSPERDAY || (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) warning(_("values over 24 hours not handled by pre-2007 versions of zic")); -- 2.7.4