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.
.\" All rights reserved.
@ -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 November 4, 2008
.Dd April 30, 2009
.Dt STRPTIME 3
.Os
.Sh NAME
@ -188,9 +188,11 @@ 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.
.Po
A
.Nx
extension.
.Pc
.It Cm \&%w
the weekday as a decimal number [0,6], with 0 representing Sunday;
leading zeros are permitted but not required.
@ -211,17 +213,64 @@ with \&%C, specifies the year [0,99] within that century.
.It Cm \&%Y
the year, including the century (i.e., 1996).
.It Cm \&%z
an ISO 8601 timezone specification.
This is either,
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
for
.Ql UTC ,
or the offset specified as:
.Dq [+-]hhmm
.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 [+-]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
.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
A
.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.
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#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
#include "namespace.h"
@ -59,6 +59,13 @@ __weak_alias(strptime,_strptime)
static char gmt[] = { "GMT" };
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 *find_string(const u_char *, int *, const char * const *,
@ -69,8 +76,8 @@ char *
strptime(const char *buf, const char *fmt, struct tm *tm)
{
unsigned char c;
const unsigned char *bp;
int alt_format, i, split_year = 0, neg, offs;
const unsigned char *bp, *ep;
int alt_format, i, split_year = 0, neg = 0, offs;
const char *new_fmt;
bp = (const u_char *)buf;
@ -320,8 +327,6 @@ literal:
#endif
bp += 3;
} else {
const unsigned char *ep;
ep = find_string(bp, &i,
(const char * const *)tzname,
NULL, 2);
@ -345,11 +350,29 @@ literal:
* [+-]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
@ -366,6 +389,49 @@ literal:
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;