This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v3 2/4] [BZ #16141] strptime: fix %z minutes calculation
- From: James Perkins <james at loowit dot net>
- To: libc-alpha at sourceware dot org
- Date: Wed, 3 Dec 2014 14:45:58 -0800
- Subject: [PATCH v3 2/4] [BZ #16141] strptime: fix %z minutes calculation
- Authentication-results: sourceware.org; auth=none
- References: <1417646760-19563-1-git-send-email-james at loowit dot net>
This is part of a fix for [BZ #16141] strptime %z offset restriction.
strptime supports a %z input field descriptor, which parses a time zone
offset from UTC time into the broken-out time field tm_gmtoff.
In the current implementation, the minutes portion calculation is
correct only for minutes evenly divisible by 3. This is because the
minutes value is converted to decimal time, but inadequate precision
leads to rounding which calculates results that are too low for some
values.
For example, due to rounding, a +1159 offset string results in an
incorrect tm_gmtoff of 43128 (== 11 * 3600 + 58.8 * 60) seconds, instead
of 43140 (== 11 * 3600 + 59 * 60) seconds. In contrast, a +1157 offset
(minutes divisible by 3) does not cause the bug, and results in a
correct tm_gmtoff of 43020.
When 'make check' is run on glibc, tst-strptime2 will report the error
with the output:
round 9: tm_gmtoff is 43056
round 10: tm_gmtoff is 43128
This fix calculates the offset from the hour and minute portions
directly, without the rounding errors introduced by decimal time.
The tst-strptime2 test succeeds with this patch applied.
James
2014-12-03 James Perkins james@loowit.net
[BZ #16141]
* time/strptime_l.c (__strptime_internal): Fix %z minutes
calculation, removing incorrect decimal time rounding, so that
all minute values result in a valid seconds value.
---
time/strptime_l.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/time/strptime_l.c b/time/strptime_l.c
index b3a612e..be35f3b 100644
--- a/time/strptime_l.c
+++ b/time/strptime_l.c
@@ -770,16 +770,12 @@ __strptime_internal (rp, fmt, tmp, statep LOCALE_PARAM)
else if (n != 4)
/* Only two or four digits recognized. */
return NULL;
- else
- {
- /* We have to convert the minutes into decimal. */
- if (val % 100 >= 60)
- return NULL;
- val = (val / 100) * 100 + ((val % 100) * 50) / 30;
- }
+ else if (val % 100 >= 60)
+ /* Minutes valid range is 0 through 59. */
+ return NULL;
if (val > 1200)
return NULL;
- tm->tm_gmtoff = (val * 3600) / 100;
+ tm->tm_gmtoff = (val / 100) * 3600 + (val % 100) * 60;
if (neg)
tm->tm_gmtoff = -tm->tm_gmtoff;
}
--
1.7.9.5