summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary E. Miller <gem@rellim.com>2018-11-08 15:41:47 -0800
committerGary E. Miller <gem@rellim.com>2018-11-08 15:41:47 -0800
commit406c477f3fc7283432bcf6522dd8d6555c7b7c1d (patch)
treee59da1660680052a0b5c475aaf12ba7a365792b7
parent613fa2733f22586899bbd64df06804cb1932380c (diff)
downloadgpsd-406c477f3fc7283432bcf6522dd8d6555c7b7c1d.tar.gz
gpsutils: fix rounding error in unix_to_iso8601(), add/fix tests.
1541766896.999512 became "2018-11-09T12:34:56.000Z". Which sould be :57. The fractional seconds got rounded up, but the seconds did not get incremented to match. Added regression tests for unix_to_iso8601(). Reported by Peter Liu <greendice@me.com>.
-rw-r--r--gpsutils.c12
-rw-r--r--test/daemon/superstar2.log.chk14
-rw-r--r--test_mktime.c48
3 files changed, 59 insertions, 15 deletions
diff --git a/gpsutils.c b/gpsutils.c
index 3070ca59..4d276626 100644
--- a/gpsutils.c
+++ b/gpsutils.c
@@ -499,11 +499,9 @@ timestamp_t iso8601_to_unix(char *isotime)
#endif /* __clang_analyzer__ */
}
-/* *INDENT-OFF* */
-char *unix_to_iso8601(timestamp_t fixtime,
- char isotime[], size_t len)
/* Unix UTC time to ISO8601, no timezone adjustment */
/* example: 2007-12-11T23:38:51.033Z */
+char *unix_to_iso8601(timestamp_t fixtime, char isotime[], size_t len)
{
struct tm when;
double integral, fractional;
@@ -512,6 +510,13 @@ char *unix_to_iso8601(timestamp_t fixtime,
char fractstr[10];
fractional = modf(fixtime, &integral);
+ /* snprintf rounding of %3f can get ugly, so pre-round */
+ if ( 0.999499999 < fractional) {
+ /* round up */
+ integral++;
+ /* give the fraction a nudge to ensure rounding */
+ fractional += 0.0005;
+ }
intfixtime = (time_t) integral;
#ifdef HAVE_GMTIME_R
(void)gmtime_r(&intfixtime, &when);
@@ -531,7 +536,6 @@ char *unix_to_iso8601(timestamp_t fixtime,
(void)snprintf(isotime, len, "%s%sZ",timestr, strchr(fractstr,'.'));
return isotime;
}
-/* *INDENT-ON* */
#define Deg2Rad(n) ((n) * DEG_2_RAD)
diff --git a/test/daemon/superstar2.log.chk b/test/daemon/superstar2.log.chk
index bd6bd50f..7da40722 100644
--- a/test/daemon/superstar2.log.chk
+++ b/test/daemon/superstar2.log.chk
@@ -7,7 +7,7 @@ $GPGGA,055054,5333.7867,N,11326.3743,W,1,05,3.10,631.80,M,,,*29
$GPRMC,055054,A,5333.7867,N,11326.3743,W,0.0000,0.000,040709,,*38
$GPGSA,A,3,29,11,1,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055054,31.47,M,35.54,M,75.90,M*02
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:54.000Z","ept":0.005,"lat":53.563112132,"lon":-113.439571599,"alt":631.801,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:50:55.000Z","ept":0.005,"lat":53.563112132,"lon":-113.439571599,"alt":631.801,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,39,03,41,063,36*7C
$GPGSV,3,2,12,28,22,023,37,09,18,156,00,30,15,073,00,23,14,223,00*72
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -17,7 +17,7 @@ $GPGGA,055055,5333.7867,N,11326.3743,W,1,05,3.10,631.87,M,,,*2F
$GPRMC,055055,A,5333.7867,N,11326.3743,W,0.0000,0.000,040709,,*39
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055055,31.47,M,35.54,M,75.90,M*03
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:55.000Z","ept":0.005,"lat":53.563111922,"lon":-113.439572138,"alt":631.867,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:50:56.000Z","ept":0.005,"lat":53.563111922,"lon":-113.439572138,"alt":631.867,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,39,03,41,063,36*7C
$GPGSV,3,2,12,28,22,023,37,09,18,156,00,30,15,073,00,23,14,223,00*72
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -27,7 +27,7 @@ $GPGGA,055056,5333.7867,N,11326.3744,W,1,05,3.10,631.94,M,,,*29
$GPRMC,055056,A,5333.7867,N,11326.3744,W,0.0000,0.000,040709,,*3D
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055056,31.47,M,35.54,M,75.90,M*00
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:56.000Z","ept":0.005,"lat":53.563111644,"lon":-113.439572583,"alt":631.943,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:50:57.000Z","ept":0.005,"lat":53.563111644,"lon":-113.439572583,"alt":631.943,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,40,03,41,063,36*72
$GPGSV,3,2,12,28,22,023,37,09,18,156,00,30,15,073,00,23,14,223,00*72
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -37,7 +37,7 @@ $GPGGA,055057,5333.7867,N,11326.3744,W,1,05,3.10,632.00,M,,,*26
$GPRMC,055057,A,5333.7867,N,11326.3744,W,0.0000,0.000,040709,,*3C
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055057,31.47,M,35.54,M,75.90,M*01
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:57.000Z","ept":0.005,"lat":53.563111100,"lon":-113.439573094,"alt":632.002,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:50:58.000Z","ept":0.005,"lat":53.563111100,"lon":-113.439573094,"alt":632.002,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,40,03,41,063,36*72
$GPGSV,3,2,12,28,22,023,36,09,18,156,00,30,15,073,00,23,14,223,00*73
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -47,7 +47,7 @@ $GPGGA,055058,5333.7866,N,11326.3744,W,1,05,3.10,632.09,M,,,*21
$GPRMC,055058,A,5333.7866,N,11326.3744,W,0.0000,0.000,040709,,*32
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055058,31.47,M,35.54,M,75.90,M*0E
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:58.000Z","ept":0.005,"lat":53.563110659,"lon":-113.439573808,"alt":632.093,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:50:59.000Z","ept":0.005,"lat":53.563110659,"lon":-113.439573808,"alt":632.093,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,39,03,41,063,36*7C
$GPGSV,3,2,12,28,22,023,37,09,18,156,00,30,15,073,00,23,14,223,00*72
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -57,7 +57,7 @@ $GPGGA,055059,5333.7866,N,11326.3745,W,1,05,3.10,632.20,M,,,*2A
$GPRMC,055059,A,5333.7866,N,11326.3745,W,0.0000,0.000,040709,,*32
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055059,31.47,M,35.54,M,75.90,M*0F
-{"class":"TPV","mode":3,"time":"2009-07-04T05:50:59.000Z","ept":0.005,"lat":53.563110309,"lon":-113.439574638,"alt":632.204,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:51:00.000Z","ept":0.005,"lat":53.563110309,"lon":-113.439574638,"alt":632.204,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,40,03,41,063,36*72
$GPGSV,3,2,12,28,22,023,36,09,18,156,00,30,15,073,00,23,14,223,00*73
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
@@ -67,7 +67,7 @@ $GPGGA,055100,5333.7866,N,11326.3745,W,1,05,3.10,632.27,M,,,*20
$GPRMC,055100,A,5333.7866,N,11326.3745,W,0.0000,0.000,040709,,*3F
$GPGSA,A,3,1,11,29,3,28,,,,,,,,5.2,3.1,3.3*34
$GPGBS,055100,31.47,M,35.54,M,75.90,M*02
-{"class":"TPV","mode":3,"time":"2009-07-04T05:51:00.000Z","ept":0.005,"lat":53.563109836,"lon":-113.439575270,"alt":632.266,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
+{"class":"TPV","mode":3,"time":"2009-07-04T05:51:01.000Z","ept":0.005,"lat":53.563109836,"lon":-113.439575270,"alt":632.266,"epx":31.470,"epy":35.543,"epv":75.900,"track":0.0000,"speed":0.000,"climb":0.000,"eps":71.09,"epc":151.80}
$GPGSV,3,1,12,01,76,110,50,11,67,212,50,29,55,030,40,03,41,063,36*72
$GPGSV,3,2,12,28,22,023,36,09,18,156,00,30,15,073,00,23,14,223,00*73
$GPGSV,3,3,12,22,06,031,00,08,01,208,00,137,28,172,00,134,26,203,00*75
diff --git a/test_mktime.c b/test_mktime.c
index 59890532..cfe0a53e 100644
--- a/test_mktime.c
+++ b/test_mktime.c
@@ -1,10 +1,13 @@
/*
+ * tests for mktime() and unix_to_iso8601().
+ *
* This file is Copyright (c) 2010 by the GPSD project
* SPDX-License-Identifier: BSD-2-clause
*/
-#include <stdlib.h>
-#include <stdio.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include "gps.h"
@@ -82,6 +85,30 @@ static struct
};
+/* tests for unit_to_iso8601() */
+static struct
+{
+ timestamp_t unixtime; /* unix time */
+ char *iso8601; /* iso8601 result */
+} tests1[] = {
+ /* time zero */
+ {(timestamp_t)0, "1970-01-01T00:00:00.000Z"},
+
+ /* before/after leap second end of 2008, notice no :60! */
+ {(timestamp_t)1230767999.01, "2008-12-31T23:59:59.010Z"},
+ {(timestamp_t)1230768000.02, "2009-01-01T00:00:00.020Z"},
+
+ /* test for rounding at %.3f */
+ {(timestamp_t)1541766896.999412, "2018-11-09T12:34:56.999Z"},
+ {(timestamp_t)1541766896.999499, "2018-11-09T12:34:56.999Z"},
+ {(timestamp_t)1541766896.999500, "2018-11-09T12:34:57.000Z"},
+ {(timestamp_t)1541766896.999501, "2018-11-09T12:34:57.000Z"},
+
+ /* the end of time: 2038 */
+ {(timestamp_t)2147483647.123456, "2038-01-19T03:14:07.123Z"},
+ {(timestamp_t)2147483648.123456, "2038-01-19T03:14:08.123Z"},
+};
+
int main(int argc UNUSED, char *argv[] UNUSED)
{
int i;
@@ -90,17 +117,30 @@ int main(int argc UNUSED, char *argv[] UNUSED)
(void)setenv("TZ", "GMT", 1);
+
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
time_t ts = mktime(&tests[i].t);
if (ts != tests[i].result) {
failed = true;
(void)strftime(tbuf, sizeof(tbuf), "%F %T", &tests[i].t);
- (void)printf("test %2d failed. "
- "Time returned from: %s should be %lu (but was: %lu)\n",
+ (void)printf("test_mktime: test %2d failed.\n"
+ " Time returned from: %s should be %lu "
+ " (but was: %lu)\n",
i, tbuf, (unsigned long)tests[i].result,
(unsigned long)ts);
}
}
+
+ /* test unix_to_iso8601() */
+ for (i = 0; i < (int)(sizeof(tests1) / sizeof(tests1[0])); i++) {
+ unix_to_iso8601(tests1[i].unixtime, tbuf, sizeof(tbuf));
+ if (0 != strcmp(tests1[i].iso8601, tbuf)) {
+ failed = true;
+ (void)printf("test_mktime: test1 %f failed.\n Got %s, s/b %s\n",
+ tests1[i].unixtime, tbuf, tests1[i].iso8601);
+ }
+ }
+
return (int)failed;
}