Extend %z to support all RFC-2822 timezone formats.

This commit is contained in:
ginsbach 2009-05-01 20:15:05 +00:00
parent b1606298a5
commit 8f7e60d3bc
2 changed files with 131 additions and 16 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: strptime.3,v 1.23 2009/03/09 19:24:27 joerg Exp $ .\" $NetBSD: strptime.3,v 1.24 2009/05/01 20:15:05 ginsbach Exp $
.\" .\"
.\" Copyright (c) 1997, 1998, 2008 The NetBSD Foundation, Inc. .\" Copyright (c) 1997, 1998, 2008 The NetBSD Foundation, Inc.
.\" All rights reserved. .\" All rights reserved.
@ -26,7 +26,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE. .\" POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd November 4, 2008 .Dd April 30, 2009
.Dt STRPTIME 3 .Dt STRPTIME 3
.Os .Os
.Sh NAME .Sh NAME
@ -188,9 +188,11 @@ year.
If it has fewer than four days in the new year, then it is considered If it has fewer than four days in the new year, then it is considered
the last week of the previous year. the last week of the previous year.
Weeks are numbered from 1 to 53. Weeks are numbered from 1 to 53.
.Po
A A
.Nx .Nx
extension. extension.
.Pc
.It Cm \&%w .It Cm \&%w
the weekday as a decimal number [0,6], with 0 representing Sunday; the weekday as a decimal number [0,6], with 0 representing Sunday;
leading zeros are permitted but not required. leading zeros are permitted but not required.
@ -211,17 +213,64 @@ with \&%C, specifies the year [0,99] within that century.
.It Cm \&%Y .It Cm \&%Y
the year, including the century (i.e., 1996). the year, including the century (i.e., 1996).
.It Cm \&%z .It Cm \&%z
an ISO 8601 timezone specification. an ISO 8601 or RFC-2822 timezone specification.
This is either, 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 .Dq Z
for .Pq Ql Zulu Time ;
.Ql UTC , a three character US timezone specified as:
or the offset specified as: .Dq EDT ,
.Dq [+-]hhmm .Dq EST ,
.Dq CDT ,
.Dq CST ,
.Dq MDT ,
.Dq MST ,
.Dq PDT ,
or or
.Dq [+-]hh:mm .Dq PST ,
with the first letter standing for
.Ql Eastern
.Pq Dq E ,
.Ql Central
.Pq Dq C ,
.Ql Mountain
.Pq Dq M
or or
.Dq [+-]hh . .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 .
.Po .Po
A A
.Nx .Nx

View File

@ -1,4 +1,4 @@
/* $NetBSD: strptime.c,v 1.31 2008/11/04 21:08:33 christos Exp $ */ /* $NetBSD: strptime.c,v 1.32 2009/05/01 20:15:05 ginsbach Exp $ */
/*- /*-
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint) #if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: strptime.c,v 1.31 2008/11/04 21:08:33 christos Exp $"); __RCSID("$NetBSD: strptime.c,v 1.32 2009/05/01 20:15:05 ginsbach Exp $");
#endif #endif
#include "namespace.h" #include "namespace.h"
@ -59,6 +59,13 @@ __weak_alias(strptime,_strptime)
static char gmt[] = { "GMT" }; static char gmt[] = { "GMT" };
static char utc[] = { "UTC" }; static char utc[] = { "UTC" };
/* 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 const u_char *conv_num(const unsigned char *, int *, uint, uint); static const u_char *conv_num(const unsigned char *, int *, uint, uint);
static const u_char *find_string(const u_char *, int *, const char * const *, static const u_char *find_string(const u_char *, int *, const char * const *,
@ -69,8 +76,8 @@ char *
strptime(const char *buf, const char *fmt, struct tm *tm) strptime(const char *buf, const char *fmt, struct tm *tm)
{ {
unsigned char c; unsigned char c;
const unsigned char *bp; const unsigned char *bp, *ep;
int alt_format, i, split_year = 0, neg, offs; int alt_format, i, split_year = 0, neg = 0, offs;
const char *new_fmt; const char *new_fmt;
bp = (const u_char *)buf; bp = (const u_char *)buf;
@ -320,8 +327,6 @@ literal:
#endif #endif
bp += 3; bp += 3;
} else { } else {
const unsigned char *ep;
ep = find_string(bp, &i, ep = find_string(bp, &i,
(const char * const *)tzname, (const char * const *)tzname,
NULL, 2); NULL, 2);
@ -345,11 +350,29 @@ literal:
* [+-]hhmm * [+-]hhmm
* [+-]hh:mm * [+-]hh:mm
* [+-]hh * [+-]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)) while (isspace(*bp))
bp++; bp++;
switch (*bp++) { switch (*bp++) {
case 'G':
if (*bp++ != 'M')
return NULL;
/*FALLTHROUGH*/
case 'U':
if (*bp++ != 'T')
return NULL;
/*FALLTHROUGH*/
case 'Z': case 'Z':
tm->tm_isdst = 0; tm->tm_isdst = 0;
#ifdef TM_GMTOFF #ifdef TM_GMTOFF
@ -366,6 +389,49 @@ literal:
neg = 1; neg = 1;
break; break;
default: 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; return NULL;
} }
offs = 0; offs = 0;