Commit a244f556 authored by Eric S. Raymond's avatar Eric S. Raymond

RFC3339/ISO8601 date formats everywhere.

As a side effect, we have to give up support for parsing RT-11 timestamps
in ntpq. Farewell, fuzzballs!
parent d0eb77ee
...@@ -95,6 +95,11 @@ object. You can read about JSON at ...@@ -95,6 +95,11 @@ object. You can read about JSON at
Be aware that if you present a tool design with a messy output format Be aware that if you present a tool design with a messy output format
and no JSON option it is quite likely to be rejected. and no JSON option it is quite likely to be rejected.
Our preferred format for dates is RFC3339 (a version of ISO8601 for
UTC with some options frozen; full year required, medial T required,
explicit Zulu timezone). Local times should be expressed in ISO8601,
always with full years and timezone offset.
=== Copyrights and licenses === === Copyrights and licenses ===
Much of the historic code in this distribution is under an "NTP Much of the historic code in this distribution is under an "NTP
......
...@@ -27,8 +27,8 @@ humanlogtime(void) ...@@ -27,8 +27,8 @@ humanlogtime(void)
LIB_GETBUF(bp); LIB_GETBUF(bp);
snprintf(bp, LIB_BUFLENGTH, "%2d %s %02d:%02d:%02d", snprintf(bp, LIB_BUFLENGTH, "%02d-%02d%02d:%02d:%02d",
tm->tm_mday, months[tm->tm_mon], tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_hour, tm->tm_min, tm->tm_sec);
return bp; return bp;
......
...@@ -18,15 +18,6 @@ ...@@ -18,15 +18,6 @@
static char *common_prettydate(l_fp *, bool); static char *common_prettydate(l_fp *, bool);
const char * const months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
const char * const daynames[7] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
/* Helper function to handle possible wraparound of the ntp epoch. /* Helper function to handle possible wraparound of the ntp epoch.
* *
* Works by periodic extension of the ntp time stamp in the UN*X epoch. * Works by periodic extension of the ntp time stamp in the UN*X epoch.
...@@ -132,9 +123,9 @@ common_prettydate( ...@@ -132,9 +123,9 @@ common_prettydate(
) )
{ {
static const char pfmt0[] = static const char pfmt0[] =
"%08lx.%08lx %s, %s %2d %4d %2d:%02d:%02d.%03u"; "%08lx.%08lx %04d-%02d-%02dT%02d:%02d:%02d.%03u";
static const char pfmt1[] = static const char pfmt1[] =
"%08lx.%08lx [%s, %s %2d %4d %2d:%02d:%02d.%03u UTC]"; "%08lx.%08lx %04d-%02d-%02dT02d:%02d:%02d.%03uZ";
char *bp; char *bp;
struct tm *tm; struct tm *tm;
...@@ -162,15 +153,13 @@ common_prettydate( ...@@ -162,15 +153,13 @@ common_prettydate(
ntpcal_time_to_date(&jd, &sec); ntpcal_time_to_date(&jd, &sec);
snprintf(bp, LIB_BUFLENGTH, local ? pfmt1 : pfmt0, snprintf(bp, LIB_BUFLENGTH, local ? pfmt1 : pfmt0,
(u_long)ts->l_ui, (u_long)ts->l_uf, (u_long)ts->l_ui, (u_long)ts->l_uf,
daynames[jd.weekday], months[jd.month-1], jd.year, jd.month, jd.monthday,
jd.monthday, jd.year, jd.hour, jd.hour, jd.minute, jd.second, msec);
jd.minute, jd.second, msec);
} else } else
snprintf(bp, LIB_BUFLENGTH, pfmt0, snprintf(bp, LIB_BUFLENGTH, pfmt0,
(u_long)ts->l_ui, (u_long)ts->l_uf, (u_long)ts->l_ui, (u_long)ts->l_uf,
daynames[tm->tm_wday], months[tm->tm_mon], 1900 + tm->tm_year, tm->tm_mon+1, tm->tm_mday,
tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour, tm->tm_hour, tm->tm_min, tm->tm_sec, msec);
tm->tm_min, tm->tm_sec, msec);
return bp; return bp;
} }
......
...@@ -3141,8 +3141,8 @@ oncore_msg_Gb( ...@@ -3141,8 +3141,8 @@ oncore_msg_Gb(
gmtm = buf[13]; gmtm = buf[13];
oncore_log_f(instance, LOG_NOTICE, oncore_log_f(instance, LOG_NOTICE,
"Date/Time set to: %d%s%d %2d:%02d:%02d GMT (GMT offset is %s%02d:%02d)", "Date/Time set to: %02d-%02d-%02dT%2d:%02d:%02d%s%02d%02d",
d, months[mo-1], y, h, m, s, gmts, gmth, gmtm); y, mo, d, h, m, s, gmts, gmth, gmtm);
} }
......
...@@ -3723,8 +3723,8 @@ mk_utcinfo( ...@@ -3723,8 +3723,8 @@ mk_utcinfo(
n += snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s", n += snprintf( t, size, "UTC offset transition from %is to %is due to leap second %s",
dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" ); dtls, dtlsf, ( dtls < dtlsf ) ? "insertion" : "deletion" );
n += snprintf( t + n, size - n, " at UTC midnight at the end of %s, %04i-%02i-%02i", n += snprintf( t + n, size - n, " at UTC midnight at the end of %04i-%02i-%02i",
daynames[tm->tm_wday], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday ); tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday );
} }
else else
snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls ); snprintf( t, size, "UTC offset parameter: %is, no leap second announced.\n", dtls );
......
...@@ -165,7 +165,6 @@ static bool getarg (const char *, int, arg_v *); ...@@ -165,7 +165,6 @@ static bool getarg (const char *, int, arg_v *);
#endif /* BUILD_AS_LIB */ #endif /* BUILD_AS_LIB */
static int findcmd (const char *, struct xcmd *, static int findcmd (const char *, struct xcmd *,
struct xcmd *, struct xcmd **); struct xcmd *, struct xcmd **);
static bool rtdatetolfp (char *, l_fp *);
static bool decodearr (char *, int *, l_fp *); static bool decodearr (char *, int *, l_fp *);
static void help (struct parse *, FILE *); static void help (struct parse *, FILE *);
static int helpsort (const void *, const void *); static int helpsort (const void *, const void *);
...@@ -1951,130 +1950,7 @@ nntohostp( ...@@ -1951,130 +1950,7 @@ nntohostp(
} }
/* /*
* rtdatetolfp - decode an RT-11 date into an l_fp * decodets - decode a hex or decimal timestamp into an l_fp format number
*/
static bool
rtdatetolfp(
char *str,
l_fp *lfp
)
{
register char *cp;
register int i;
struct calendar cal;
char buf[4];
cal.yearday = 0;
/*
* An RT-11 date looks like:
*
* d[d]-Mth-y[y] hh:mm:ss
*
* (No docs, but assume 4-digit years are also legal...)
*
* d[d]-Mth-y[y[y[y]]] hh:mm:ss
*/
cp = str;
if (!isdigit((int)*cp)) {
if (*cp == '-') {
/*
* Catch special case
*/
L_CLR(lfp);
return true;
}
return false;
}
cal.monthday = (uint8_t) (*cp++ - '0'); /* ascii dependent */
if (isdigit((int)*cp)) {
cal.monthday = (uint8_t)((cal.monthday << 3) + (cal.monthday << 1));
cal.monthday = (uint8_t)(cal.monthday + *cp++ - '0');
}
if (*cp++ != '-')
return false;
for (i = 0; i < 3; i++)
buf[i] = *cp++;
buf[3] = '\0';
for (i = 0; i < 12; i++)
if (STREQ(buf, months[i]))
break;
if (i == 12)
return false;
cal.month = (uint8_t)(i + 1);
if (*cp++ != '-')
return false;
if (!isdigit((int)*cp))
return false;
cal.year = (u_short)(*cp++ - '0');
if (isdigit((int)*cp)) {
cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
cal.year = (u_short)(*cp++ - '0');
}
if (isdigit((int)*cp)) {
cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
cal.year = (u_short)(cal.year + *cp++ - '0');
}
if (isdigit((int)*cp)) {
cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
cal.year = (u_short)(cal.year + *cp++ - '0');
}
/*
* Catch special case. If cal.year == 0 this is a zero timestamp.
*/
if (cal.year == 0) {
L_CLR(lfp);
return true;
}
if (*cp++ != ' ' || !isdigit((int)*cp))
return false;
cal.hour = (uint8_t)(*cp++ - '0');
if (isdigit((int)*cp)) {
cal.hour = (uint8_t)((cal.hour << 3) + (cal.hour << 1));
cal.hour = (uint8_t)(cal.hour + *cp++ - '0');
}
if (*cp++ != ':' || !isdigit((int)*cp))
return false;
cal.minute = (uint8_t)(*cp++ - '0');
if (isdigit((int)*cp)) {
cal.minute = (uint8_t)((cal.minute << 3) + (cal.minute << 1));
cal.minute = (uint8_t)(cal.minute + *cp++ - '0');
}
if (*cp++ != ':' || !isdigit((int)*cp))
return false;
cal.second = (uint8_t)(*cp++ - '0');
if (isdigit((int)*cp)) {
cal.second = (uint8_t)((cal.second << 3) + (cal.second << 1));
cal.second = (uint8_t)(cal.second + *cp++ - '0');
}
/*
* For RT-11, 1972 seems to be the pivot year
*/
if (cal.year < 72)
cal.year += 2000;
if (cal.year < 100)
cal.year += 1900;
lfp->l_ui = caltontp(&cal);
lfp->l_uf = false;
return true;
}
/*
* decodets - decode a timestamp into an l_fp format number, with
* consideration of fuzzball formats.
*/ */
bool bool
decodets( decodets(
...@@ -2082,29 +1958,12 @@ decodets( ...@@ -2082,29 +1958,12 @@ decodets(
l_fp *lfp l_fp *lfp
) )
{ {
char *cp;
char buf[30];
size_t b;
/* /*
* If it starts with a 0x, decode as hex. * If it starts with a 0x, decode as hex.
*/ */
if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
return hextolfp(str+2, lfp); return hextolfp(str+2, lfp);
/*
* If it starts with a '"', try it as an RT-11 date.
*/
if (*str == '"') {
cp = str + 1;
b = 0;
while ('"' != *cp && '\0' != *cp &&
b < COUNTOF(buf) - 1)
buf[b++] = *cp++;
buf[b] = '\0';
return rtdatetolfp(buf, lfp);
}
/* /*
* Might still be hex. Check out the first character. Talk * Might still be hex. Check out the first character. Talk
* about heuristics! * about heuristics!
...@@ -2119,7 +1978,7 @@ decodets( ...@@ -2119,7 +1978,7 @@ decodets(
if (atolfp(str, lfp)) if (atolfp(str, lfp))
return true; return true;
return rtdatetolfp(str, lfp); return false;
} }
......
...@@ -23,5 +23,5 @@ protected: ...@@ -23,5 +23,5 @@ protected:
TEST(prettydate, ConstantDate) { TEST(prettydate, ConstantDate) {
l_fp time = {3485080800UL, HALF}; // 2010-06-09 14:00:00.5 l_fp time = {3485080800UL, HALF}; // 2010-06-09 14:00:00.5
TEST_ASSERT_EQUAL_STRING("cfba1ce0.80000000 Wed, Jun 9 2010 14:00:00.500", gmprettydate(&time)); TEST_ASSERT_EQUAL_STRING("cfba1ce0.80000000 2010-06-09T14:00:00.500", gmprettydate(&time));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment