Index: lib/libc/stdtime/strptime.3 =================================================================== --- lib/libc/stdtime/strptime.3 +++ lib/libc/stdtime/strptime.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" " -.Dd October 2, 2014 +.Dd February 28, 2020 .Dt STRPTIME 3 .Os .Sh NAME @@ -80,12 +80,22 @@ are now interpreted as beginning at 1969 per POSIX requirements. Years 69-00 are interpreted in the 20th century (1969-2000), years 01-68 in the 21st century (2001-2068). +Four-digit year values in +.Fa \&%Y +specifier are interpreted as days since year 1900 +as per POSIX requirements. The .Fa \&%U and .Fa %W format specifiers accept any value within the range 00 to 53. .Pp +The time zone +.Fa \&%z +format specifier accepts both RFC 822 (+hhmm) and ISO 8601 (+hhmm +hh:mm +hh Z) +standard time zone formats. +The -00, -00:00, -0000 time zone values are also accepted as per RFC 3339. +.Pp If the .Fa format string does not contain enough conversion specifications to completely Index: lib/libc/stdtime/strptime.c =================================================================== --- lib/libc/stdtime/strptime.c +++ lib/libc/stdtime/strptime.c @@ -573,26 +573,39 @@ case 'z': { int sign = 1; + len = 4; /* RFC 822/ISO 8601 */ if (*buf != '+') { if (*buf == '-') sign = -1; + else if (*buf == 'Z') /* ISO 8601 Z (UTC) */ + len = 0; else return (NULL); } buf++; i = 0; - for (len = 4; len > 0; len--) { + for (; len > 0; len--) { if (isdigit_l((unsigned char)*buf, locale)) { i *= 10; i += *buf - '0'; buf++; + } else if (*buf == ':' && len == 2) { + buf++; /* ISO 8601 +hh:mm */ + if (isdigit_l((unsigned char)*buf, locale)) { + i *= 10; + i += *buf - '0'; + buf++; + } else { + return (NULL); + } } else if (len == 2) { - i *= 100; + i *= 100; /* ISO 8601 +hh */ break; - } else + } else { return (NULL); + } } if (i > 1400 || (sign == -1 && i > 1200) ||