diff options
author | Jasper Lievisse Adriaanse <jasper@cvs.openbsd.org> | 2010-11-08 19:16:17 +0000 |
---|---|---|
committer | Jasper Lievisse Adriaanse <jasper@cvs.openbsd.org> | 2010-11-08 19:16:17 +0000 |
commit | fbf32c45c8de6dce36798fbcf77e8fae843ab626 (patch) | |
tree | 396c80edfd3492350f64520a1e804b9bdb9e6ad9 /lib | |
parent | 4171d7225d2a6401e152b6bf90d7fc117d4d1ae9 (diff) |
Add %F, %g, %G, %u, %z (extended) and %Z.
This is mostly a sync with NetBSD.
tested in a bulk build by landry@
ok millert@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/time/strptime.3 | 107 | ||||
-rw-r--r-- | lib/libc/time/strptime.c | 236 |
2 files changed, 334 insertions, 9 deletions
diff --git a/lib/libc/time/strptime.3 b/lib/libc/time/strptime.3 index e80df22b21d..a8383c9fdaf 100644 --- a/lib/libc/time/strptime.3 +++ b/lib/libc/time/strptime.3 @@ -1,6 +1,6 @@ -.\" $OpenBSD: strptime.3,v 1.13 2010/04/12 01:17:33 tedu Exp $ +.\" $OpenBSD: strptime.3,v 1.14 2010/11/08 19:16:16 jasper Exp $ .\" -.\" Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. +.\" Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. .\" All rights reserved. .\" .\" This file was contributed to The NetBSD Foundation by Klaus Klein. @@ -26,7 +26,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: April 12 2010 $ +.Dd $Mdocdate: November 8 2010 $ .Dt STRPTIME 3 .Os .Sh NAME @@ -95,6 +95,13 @@ the date as %m/%d/%y. .It Cm \&%e the same as .Cm \&%d . +.It Cm \&%F +the date as %Y-%m-%d +(the ISO 8601 date format). +.It Cm \&%g +the year corresponding to the ISO week number, without the century. +.It Cm \&%G +the year corresponding to the ISO week number, with the century. .It Cm \&%h the same as .Cm \&%b . @@ -137,11 +144,21 @@ leading zeros are permitted but not required. any whitespace. .It Cm \&%T the time as %H:%M:%S. +.It Cm \&%u +the day of the week as a decimal number, where Monday = 1. .It Cm \&%U the week number of the year (Sunday as the first day of the week) as a decimal number [0,53]; leading zeros are permitted but not required. All days in a year preceding the first Sunday are considered to be in week 0. +.It Cm \&%V +the ISO 8601:1988 week number as a decimal number. +If the week (starting on Monday) that contains January 1 has more than +three days in the new year, then it is considered the first week of the +year. +If it has fewer than four days in the new year, then it is considered +the last week of the previous year. +Weeks are numbered from 1 to 53. .It Cm \&%w the weekday as a decimal number [0,6], with 0 representing Sunday; leading zeros are permitted but not required. @@ -163,7 +180,68 @@ to years in the twenty-first century (2000 to 2068 inclusive). Leading zeros are permitted but not required. .It Cm \&%Y the year, including the century (i.e., 1998). -.It Cm \&%% +.It Cm \&%z +an ISO 8601 or RFC-2822 timezone specification. +This is one of the following: +the offset from +Coordinated Universal Time +.Pq Ql UTC +specified as: +.Dq [+-]hhmm , +.Dq [+-]hh:mm , +or +.Dq [+-]hh ; +.Ql UTC +specified as: +.Dq GMT +.Pq Ql Greenwich Mean Time , +.Dq UT +.Pq Ql Universal Time , +or +.Dq Z +.Pq Ql Zulu Time ; +a three character US timezone specified as: +.Dq EDT , +.Dq EST , +.Dq CDT , +.Dq CST , +.Dq MDT , +.Dq MST , +.Dq PDT , +or +.Dq PST , +with the first letter standing for +.Ql Eastern +.Pq Dq E , +.Ql Central +.Pq Dq C , +.Ql Mountain +.Pq Dq M +or +.Ql Pacific +.Pq Dq P , +and the second letter standing for +.Ql Daylight +.Po +.Dq D +or summer +.Pc +time +or +.Ql Standard +.Pq Dq S +time; +a single letter military timezone specified as: +.Dq A +through +.Dq I +and +.Dq K +through +.Dq Y . +.It Cm \&%Z +timezone name or no characters when time zone information is unavailable. +It Cm \&%% A `%' is read. No argument is converted. .El @@ -210,3 +288,24 @@ The .Fn strptime function conforms to .St -xpg4.2 . +.Pp +The +.Ql \&%G , +.Ql \&%g , +.Ql \&%u , +.Ql \&%V , +.Ql \&%Y , +and +.Ql \&%Z +conversion specifications are extensions. +.Sh BUGS +The +.Cm \&%Z +format specifier only accepts timezone +abbreviations of the local timezone, +or the value +.Dq GMT . +This limitation is caused by the ambiguity +of overloaded timezone abbreviations, +for example EST is both Eastern Standard +Time and Eastern Australia Summer Time. diff --git a/lib/libc/time/strptime.c b/lib/libc/time/strptime.c index d5c09107c1d..31baa6f0710 100644 --- a/lib/libc/time/strptime.c +++ b/lib/libc/time/strptime.c @@ -1,8 +1,8 @@ -/* $OpenBSD: strptime.c,v 1.12 2008/06/26 05:42:05 ray Exp $ */ +/* $OpenBSD: strptime.c,v 1.13 2010/11/08 19:16:16 jasper Exp $ */ /* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */ /*- - * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * All rights reserved. * * This code was contributed to The NetBSD Foundation by Klaus Klein. @@ -46,9 +46,22 @@ #define _ALT_O 0x02 #define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); } +static char gmt[] = { "GMT" }; +#ifdef TM_ZONE +static char utc[] = { "UTC" }; +#endif +/* RFC-822/RFC-2822 */ +static const char * const nast[5] = { + "EST", "CST", "MST", "PST", "\0\0\0" +}; +static const char * const nadt[5] = { + "EDT", "CDT", "MDT", "PDT", "\0\0\0" +}; static int _conv_num(const unsigned char **, int *, int, int); static char *_strptime(const char *, const char *, struct tm *, int); +static const u_char *_find_string(const u_char *, int *, const char * const *, + const char * const *, int); char * @@ -61,9 +74,10 @@ static char * _strptime(const char *buf, const char *fmt, struct tm *tm, int initialize) { unsigned char c; - const unsigned char *bp; + const unsigned char *bp, *ep; size_t len; - int alt_format, i; + int alt_format, i, offs; + int neg = 0; static int century, relyear; if (initialize) { @@ -125,7 +139,13 @@ literal: if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0))) return (NULL); break; - + + case 'F': /* The date as "%Y-%m-%d". */ + _LEGAL_ALT(0); + if (!(bp = _strptime(bp, "%Y/%m/%d", tm, 0))) + return (NULL); + continue; + case 'R': /* The time as "%H:%M". */ _LEGAL_ALT(0); if (!(bp = _strptime(bp, "%H:%M", tm, 0))) @@ -312,6 +332,33 @@ literal: return (NULL); break; + case 'u': /* The day of week, monday = 1. */ + _LEGAL_ALT(_ALT_O); + if (!(_conv_num(&bp, &i, 1, 7))) + return (NULL); + tm->tm_wday = i % 7; + continue; + + case 'g': /* The year corresponding to the ISO week + * number but without the century. + */ + if (!(_conv_num(&bp, &i, 0, 99))) + return (NULL); + continue; + + case 'G': /* The year corresponding to the ISO week + * number with century. + */ + do + bp++; + while (isdigit(*bp)); + continue; + + case 'V': /* The ISO 8601:1988 week number as decimal */ + if (!(_conv_num(&bp, &i, 0, 53))) + return (NULL); + continue; + case 'Y': /* The year. */ _LEGAL_ALT(_ALT_E); if (!(_conv_num(&bp, &i, 0, 9999))) @@ -327,6 +374,163 @@ literal: return (NULL); break; + case 'Z': + tzset(); + if (strncmp((const char *)bp, gmt, 3) == 0) { + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = gmt; +#endif + bp += 3; + } else { + ep = _find_string(bp, &i, + (const char * const *)tzname, + NULL, 2); + if (ep != NULL) { + tm->tm_isdst = i; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -(timezone); +#endif +#ifdef TM_ZONE + tm->TM_ZONE = tzname[i]; +#endif + } + bp = ep; + } + continue; + + case 'z': + /* + * We recognize all ISO 8601 formats: + * Z = Zulu time/UTC + * [+-]hhmm + * [+-]hh:mm + * [+-]hh + * We recognize all RFC-822/RFC-2822 formats: + * UT|GMT + * North American : UTC offsets + * E[DS]T = Eastern : -4 | -5 + * C[DS]T = Central : -5 | -6 + * M[DS]T = Mountain: -6 | -7 + * P[DS]T = Pacific : -7 | -8 + * Military + * [A-IL-M] = -1 ... -9 (J not used) + * [N-Y] = +1 ... +12 + */ + while (isspace(*bp)) + bp++; + + switch (*bp++) { + case 'G': + if (*bp++ != 'M') + return NULL; + /*FALLTHROUGH*/ + case 'U': + if (*bp++ != 'T') + return NULL; + /*FALLTHROUGH*/ + case 'Z': + tm->tm_isdst = 0; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = 0; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = utc; +#endif + continue; + case '+': + neg = 0; + break; + case '-': + neg = 1; + break; + default: + --bp; + ep = _find_string(bp, &i, nast, NULL, 4); + if (ep != NULL) { +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -5 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nast[i]); +#endif + bp = ep; + continue; + } + ep = _find_string(bp, &i, nadt, NULL, 4); + if (ep != NULL) { + tm->tm_isdst = 1; +#ifdef TM_GMTOFF + tm->TM_GMTOFF = -4 - i; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = __UNCONST(nadt[i]); +#endif + bp = ep; + continue; + } + + if ((*bp >= 'A' && *bp <= 'I') || + (*bp >= 'L' && *bp <= 'Y')) { +#ifdef TM_GMTOFF + /* Argh! No 'J'! */ + if (*bp >= 'A' && *bp <= 'I') + tm->TM_GMTOFF = + ('A' - 1) - (int)*bp; + else if (*bp >= 'L' && *bp <= 'M') + tm->TM_GMTOFF = 'A' - (int)*bp; + else if (*bp >= 'N' && *bp <= 'Y') + tm->TM_GMTOFF = (int)*bp - 'M'; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + bp++; + continue; + } + return NULL; + } + offs = 0; + for (i = 0; i < 4; ) { + if (isdigit(*bp)) { + offs = offs * 10 + (*bp++ - '0'); + i++; + continue; + } + if (i == 2 && *bp == ':') { + bp++; + continue; + } + break; + } + switch (i) { + case 2: + offs *= 100; + break; + case 4: + i = offs % 100; + if (i >= 60) + return NULL; + /* Convert minutes into decimal */ + offs = (offs / 100) * 100 + (i * 50) / 30; + break; + default: + return NULL; + } + if (neg) + offs = -offs; + tm->tm_isdst = 0; /* XXX */ +#ifdef TM_GMTOFF + tm->TM_GMTOFF = offs; +#endif +#ifdef TM_ZONE + tm->TM_ZONE = NULL; /* XXX */ +#endif + continue; + /* * Miscellaneous conversions. */ @@ -386,3 +590,25 @@ _conv_num(const unsigned char **buf, int *dest, int llim, int ulim) *dest = result; return (1); } + +static const u_char * +_find_string(const u_char *bp, int *tgt, const char * const *n1, + const char * const *n2, int c) +{ + int i; + unsigned int len; + + /* check full name - then abbreviated ones */ + for (; n1 != NULL; n1 = n2, n2 = NULL) { + for (i = 0; i < c; i++, n1++) { + len = strlen(*n1); + if (strncasecmp(*n1, (const char *)bp, len) == 0) { + *tgt = i; + return bp + len; + } + } + } + + /* Nothing matched */ + return NULL; +} |