PR/50380: Balazs Scheidler: strptime() returns incorrect values in tm_gmtoff
- Always offset in seconds. - Handle arbitrary timezones.
This commit is contained in:
parent
37de2f9dd3
commit
4ba084a19e
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: strptime.3,v 1.31 2015/04/06 14:38:22 ginsbach Exp $
|
||||
.\" $NetBSD: strptime.3,v 1.32 2015/10/29 17:54:49 christos Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1997, 1998, 2008 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
|
@ -223,33 +223,56 @@ the year, including the century (i.e., 1996).
|
|||
.It Cm \&%z
|
||||
an ISO 8601 or RFC-2822 time zone specification.
|
||||
This is one of the following:
|
||||
the offset from
|
||||
Coordinated Universal Time
|
||||
.Bl -dash -offset indent -compact
|
||||
.It
|
||||
The offset from Coordinated Universal Time
|
||||
.Pq Ql UTC
|
||||
specified as:
|
||||
.Dq [+-]hhmm ,
|
||||
.Dq [+-]hh:mm ,
|
||||
or
|
||||
.Dq [+-]hh ;
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
[+-]hhmm
|
||||
.It
|
||||
[+-]hh:mm
|
||||
.It
|
||||
[+-]hh
|
||||
.El
|
||||
.It
|
||||
.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 time zone specified as:
|
||||
.Dq EDT ,
|
||||
.Dq EST ,
|
||||
.Dq CDT ,
|
||||
.Dq CST ,
|
||||
.Dq MDT ,
|
||||
.Dq MST ,
|
||||
.Dq PDT ,
|
||||
or
|
||||
.Dq PST ,
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
UTC
|
||||
.Pq Ql Coordinated Universal time
|
||||
.It
|
||||
GMT
|
||||
.Pq Ql Greenwich Mean Time
|
||||
.It
|
||||
UT
|
||||
.Pq Ql Universal Time
|
||||
.It
|
||||
Z
|
||||
.Pq Ql Zulu Time
|
||||
.El
|
||||
.It
|
||||
A three character US time zone specified as:
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
EDT
|
||||
.It
|
||||
EST
|
||||
.It
|
||||
CDT
|
||||
.It
|
||||
CST
|
||||
.It
|
||||
MDT
|
||||
.It
|
||||
MST
|
||||
.It
|
||||
PDT
|
||||
.It
|
||||
PST
|
||||
.El
|
||||
with the first letter standing for
|
||||
.Ql Eastern
|
||||
.Pq Dq E ,
|
||||
|
@ -270,15 +293,22 @@ time
|
|||
or
|
||||
.Ql Standard
|
||||
.Pq Dq S
|
||||
time;
|
||||
time
|
||||
.It
|
||||
a single letter military time zone specified as:
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
.Dq A
|
||||
through
|
||||
.Dq I
|
||||
and
|
||||
.It
|
||||
.Dq K
|
||||
through
|
||||
.Dq Y .
|
||||
.El
|
||||
.It
|
||||
An arbirtrary timezone name that can be loaded from the database.
|
||||
.El
|
||||
.Po
|
||||
A
|
||||
.Nx
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: strptime.c,v 1.49 2015/10/09 17:21:45 christos Exp $ */
|
||||
/* $NetBSD: strptime.c,v 1.50 2015/10/29 17:54:49 christos 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.49 2015/10/09 17:21:45 christos Exp $");
|
||||
__RCSID("$NetBSD: strptime.c,v 1.50 2015/10/29 17:54:49 christos Exp $");
|
||||
#endif
|
||||
|
||||
#include "namespace.h"
|
||||
|
@ -114,6 +114,34 @@ first_wday_of(int yr)
|
|||
(isleap(yr) ? 6 : 0) + 1) % 7;
|
||||
}
|
||||
|
||||
#define delim(p) ((p) == '\0' || isspace((unsigned char)(p)))
|
||||
|
||||
static int
|
||||
fromzone(const unsigned char **bp, struct tm *tm)
|
||||
{
|
||||
timezone_t tz;
|
||||
char buf[512], *p;
|
||||
|
||||
for (p = buf; !delim(**bp) && p < &buf[sizeof(buf) - 1]; (*bp)++)
|
||||
*p++ = **bp;
|
||||
*p = '\0';
|
||||
|
||||
tz = tzalloc(buf);
|
||||
if (tz == NULL)
|
||||
return 0;
|
||||
|
||||
tm->tm_isdst = 0; /* XXX */
|
||||
#ifdef TM_GMTOFF
|
||||
tm->TM_GMTOFF = tzgetgmtoff(tz, tm->tm_isdst);
|
||||
#endif
|
||||
#ifdef TM_ZONE
|
||||
// Can't use tzgetname() here because we are going to free()
|
||||
tm->TM_ZONE = utc; /* XXX */
|
||||
#endif
|
||||
tzfree(tz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *
|
||||
strptime(const char *buf, const char *fmt, struct tm *tm)
|
||||
{
|
||||
|
@ -124,7 +152,7 @@ char *
|
|||
strptime_l(const char *buf, const char *fmt, struct tm *tm, locale_t loc)
|
||||
{
|
||||
unsigned char c;
|
||||
const unsigned char *bp, *ep;
|
||||
const unsigned char *bp, *ep, *zname;
|
||||
int alt_format, i, split_year = 0, neg = 0, state = 0,
|
||||
day_offset = -1, week_offset = 0, offs;
|
||||
const char *new_fmt;
|
||||
|
@ -439,13 +467,18 @@ literal:
|
|||
if (ep != NULL) {
|
||||
tm->tm_isdst = i;
|
||||
#ifdef TM_GMTOFF
|
||||
tm->TM_GMTOFF = -(timezone);
|
||||
#ifdef USG_COMPAT
|
||||
tm->TM_GMTOFF = -timezone;
|
||||
#else
|
||||
tm->TM_GMTOFF = -timezone();
|
||||
#endif
|
||||
#endif
|
||||
#ifdef TM_ZONE
|
||||
tm->TM_ZONE = tzname[i];
|
||||
bp = ep;
|
||||
#endif
|
||||
}
|
||||
bp = ep;
|
||||
} else
|
||||
(void)fromzone(&bp, tm);
|
||||
}
|
||||
continue;
|
||||
|
||||
|
@ -470,16 +503,21 @@ literal:
|
|||
while (isspace(*bp))
|
||||
bp++;
|
||||
|
||||
zname = bp;
|
||||
switch (*bp++) {
|
||||
case 'G':
|
||||
if (*bp++ != 'M')
|
||||
return NULL;
|
||||
goto namedzone;
|
||||
/*FALLTHROUGH*/
|
||||
case 'U':
|
||||
if (*bp++ != 'T')
|
||||
return NULL;
|
||||
goto namedzone;
|
||||
else if (!delim(*bp) && *bp++ != 'C')
|
||||
goto namedzone;
|
||||
/*FALLTHROUGH*/
|
||||
case 'Z':
|
||||
if (!delim(*bp))
|
||||
goto namedzone;
|
||||
tm->tm_isdst = 0;
|
||||
#ifdef TM_GMTOFF
|
||||
tm->TM_GMTOFF = 0;
|
||||
|
@ -495,11 +533,42 @@ literal:
|
|||
neg = 1;
|
||||
break;
|
||||
default:
|
||||
--bp;
|
||||
namedzone:
|
||||
bp = zname;
|
||||
|
||||
/* Military style */
|
||||
if (delim(bp[1]) &&
|
||||
((*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';
|
||||
tm->TM_GMTOFF *= 3600;
|
||||
#endif
|
||||
#ifdef TM_ZONE
|
||||
tm->TM_ZONE = utc; /* XXX */
|
||||
#endif
|
||||
bp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* From our 3 letter hard-coded table
|
||||
* XXX: Can be removed, handled by tzload()
|
||||
*/
|
||||
if (delim(bp[0]) || delim(bp[1]) ||
|
||||
delim(bp[2]) || !delim(bp[3]))
|
||||
goto loadzone;
|
||||
ep = find_string(bp, &i, nast, NULL, 4);
|
||||
if (ep != NULL) {
|
||||
#ifdef TM_GMTOFF
|
||||
tm->TM_GMTOFF = -5 - i;
|
||||
tm->TM_GMTOFF = (-5 - i) * 3600;
|
||||
#endif
|
||||
#ifdef TM_ZONE
|
||||
tm->TM_ZONE = __UNCONST(nast[i]);
|
||||
|
@ -511,7 +580,7 @@ literal:
|
|||
if (ep != NULL) {
|
||||
tm->tm_isdst = 1;
|
||||
#ifdef TM_GMTOFF
|
||||
tm->TM_GMTOFF = -4 - i;
|
||||
tm->TM_GMTOFF = (-4 - i) * 3600;
|
||||
#endif
|
||||
#ifdef TM_ZONE
|
||||
tm->TM_ZONE = __UNCONST(nadt[i]);
|
||||
|
@ -520,24 +589,12 @@ literal:
|
|||
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 = utc; /* XXX */
|
||||
#endif
|
||||
bp++;
|
||||
loadzone:
|
||||
/*
|
||||
* The hard way, load the zone!
|
||||
*/
|
||||
if (fromzone(&bp, tm))
|
||||
continue;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
offs = 0;
|
||||
|
@ -553,16 +610,18 @@ literal:
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (isdigit(*bp))
|
||||
return NULL;
|
||||
switch (i) {
|
||||
case 2:
|
||||
offs *= 100;
|
||||
offs *= 3600;
|
||||
break;
|
||||
case 4:
|
||||
i = offs % 100;
|
||||
if (i >= 60)
|
||||
return NULL;
|
||||
/* Convert minutes into decimal */
|
||||
offs = (offs / 100) * 100 + (i * 50) / 30;
|
||||
offs = (offs / 100) * 3600 + i * 60;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
|
Loading…
Reference in New Issue