diff options
author | Gary E. Miller <gem@rellim.com> | 2018-11-08 15:41:47 -0800 |
---|---|---|
committer | Gary E. Miller <gem@rellim.com> | 2018-11-08 15:41:47 -0800 |
commit | 406c477f3fc7283432bcf6522dd8d6555c7b7c1d (patch) | |
tree | e59da1660680052a0b5c475aaf12ba7a365792b7 | |
parent | 613fa2733f22586899bbd64df06804cb1932380c (diff) | |
download | gpsd-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.c | 12 | ||||
-rw-r--r-- | test/daemon/superstar2.log.chk | 14 | ||||
-rw-r--r-- | test_mktime.c | 48 |
3 files changed, 59 insertions, 15 deletions
@@ -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; } |