strptime.c revision 207830
128019Sjoerg/*
228021Sjoerg * Powerdog Industries kindly requests feedback from anyone modifying
328021Sjoerg * this function:
428021Sjoerg *
528021Sjoerg * Date: Thu, 05 Jun 1997 23:17:17 -0400
628021Sjoerg * From: Kevin Ruddy <kevin.ruddy@powerdog.com>
728021Sjoerg * To: James FitzGibbon <james@nexis.net>
828021Sjoerg * Subject: Re: Use of your strptime(3) code (fwd)
928021Sjoerg *
1028021Sjoerg * The reason for the "no mod" clause was so that modifications would
1128021Sjoerg * come back and we could integrate them and reissue so that a wider
1228021Sjoerg * audience could use it (thereby spreading the wealth).  This has
1328021Sjoerg * made it possible to get strptime to work on many operating systems.
1428021Sjoerg * I'm not sure why that's "plain unacceptable" to the FreeBSD team.
1528021Sjoerg *
1628021Sjoerg * Anyway, you can change it to "with or without modification" as
1728021Sjoerg * you see fit.  Enjoy.
1828021Sjoerg *
1928021Sjoerg * Kevin Ruddy
2028021Sjoerg * Powerdog Industries, Inc.
2128021Sjoerg */
2228021Sjoerg/*
2328019Sjoerg * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
2428019Sjoerg *
2528021Sjoerg * Redistribution and use in source and binary forms, with or without
2628019Sjoerg * modification, are permitted provided that the following conditions
2728019Sjoerg * are met:
2828019Sjoerg * 1. Redistributions of source code must retain the above copyright
2928019Sjoerg *    notice, this list of conditions and the following disclaimer.
3028019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
3128019Sjoerg *    notice, this list of conditions and the following disclaimer
3228019Sjoerg *    in the documentation and/or other materials provided with the
3328019Sjoerg *    distribution.
3428019Sjoerg * 3. All advertising materials mentioning features or use of this
3528019Sjoerg *    software must display the following acknowledgement:
3628019Sjoerg *      This product includes software developed by Powerdog Industries.
3728019Sjoerg * 4. The name of Powerdog Industries may not be used to endorse or
3828019Sjoerg *    promote products derived from this software without specific prior
3928019Sjoerg *    written permission.
4028019Sjoerg *
4128019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
4228019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4328019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4428019Sjoerg * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
4528019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4628019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4728019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4828019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4928019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5028019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5128019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5228019Sjoerg */
5328019Sjoerg
54111010Snectar#include <sys/cdefs.h>
5528019Sjoerg#ifndef lint
5628021Sjoerg#ifndef NOID
57111010Snectarstatic char copyright[] __unused =
5828019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
59111010Snectarstatic char sccsid[] __unused = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
6028021Sjoerg#endif /* !defined NOID */
6128019Sjoerg#endif /* not lint */
6292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdtime/strptime.c 207830 2010-05-09 22:01:35Z edwin $");
6328019Sjoerg
6471579Sdeischen#include "namespace.h"
6528019Sjoerg#include <time.h>
6628019Sjoerg#include <ctype.h>
67122830Snectar#include <errno.h>
6879664Sdd#include <stdlib.h>
6928019Sjoerg#include <string.h>
7048614Sobrien#include <pthread.h>
7171579Sdeischen#include "un-namespace.h"
7271579Sdeischen#include "libc_private.h"
7328021Sjoerg#include "timelocal.h"
7428019Sjoerg
75112156Smtmstatic char * _strptime(const char *, const char *, struct tm *, int *);
7648614Sobrien
7728021Sjoerg#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
7828019Sjoerg
7948614Sobrienstatic char *
80112156Smtm_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
8128019Sjoerg{
8228021Sjoerg	char	c;
8328021Sjoerg	const char *ptr;
8428021Sjoerg	int	i,
8528021Sjoerg		len;
8653941Sache	int Ealternative, Oalternative;
8772168Sphantom	struct lc_time_T *tptr = __get_current_time_locale();
8828019Sjoerg
8928021Sjoerg	ptr = fmt;
9028021Sjoerg	while (*ptr != 0) {
9128021Sjoerg		if (*buf == 0)
9228021Sjoerg			break;
9328019Sjoerg
9428021Sjoerg		c = *ptr++;
9528019Sjoerg
9628021Sjoerg		if (c != '%') {
9728164Sache			if (isspace((unsigned char)c))
9828164Sache				while (*buf != 0 && isspace((unsigned char)*buf))
9928021Sjoerg					buf++;
10028021Sjoerg			else if (c != *buf++)
10128021Sjoerg				return 0;
10228021Sjoerg			continue;
10328021Sjoerg		}
10428019Sjoerg
10553941Sache		Ealternative = 0;
10653941Sache		Oalternative = 0;
10753941Sachelabel:
10828021Sjoerg		c = *ptr++;
10928021Sjoerg		switch (c) {
11028021Sjoerg		case 0:
11128021Sjoerg		case '%':
11228021Sjoerg			if (*buf++ != '%')
11328021Sjoerg				return 0;
11428021Sjoerg			break;
11528019Sjoerg
11653941Sache		case '+':
117112156Smtm			buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
11828021Sjoerg			if (buf == 0)
11928021Sjoerg				return 0;
12028021Sjoerg			break;
12128019Sjoerg
12253941Sache		case 'C':
12353941Sache			if (!isdigit((unsigned char)*buf))
12453941Sache				return 0;
12553941Sache
12654316Ssheldonh			/* XXX This will break for 3-digit centuries. */
12754316Ssheldonh			len = 2;
12854316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
12953941Sache				i *= 10;
13053941Sache				i += *buf - '0';
13154316Ssheldonh				len--;
13253941Sache			}
13353941Sache			if (i < 19)
13453941Sache				return 0;
13553941Sache
13653941Sache			tm->tm_year = i * 100 - 1900;
13753941Sache			break;
13853941Sache
13928021Sjoerg		case 'c':
140112156Smtm			buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
14128021Sjoerg			if (buf == 0)
14228021Sjoerg				return 0;
14328021Sjoerg			break;
14428019Sjoerg
14528021Sjoerg		case 'D':
146112156Smtm			buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
14728021Sjoerg			if (buf == 0)
14828021Sjoerg				return 0;
14928021Sjoerg			break;
15028019Sjoerg
15153941Sache		case 'E':
15253960Sache			if (Ealternative || Oalternative)
15353960Sache				break;
15453941Sache			Ealternative++;
15553941Sache			goto label;
15653941Sache
15753941Sache		case 'O':
15853960Sache			if (Ealternative || Oalternative)
15953960Sache				break;
16053941Sache			Oalternative++;
16153941Sache			goto label;
16253941Sache
16353960Sache		case 'F':
164112156Smtm			buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
16574412Sache			if (buf == 0)
16674412Sache				return 0;
16774412Sache			break;
16874412Sache
16928021Sjoerg		case 'R':
170112156Smtm			buf = _strptime(buf, "%H:%M", tm, GMTp);
17128021Sjoerg			if (buf == 0)
17228021Sjoerg				return 0;
17328021Sjoerg			break;
17428019Sjoerg
17528021Sjoerg		case 'r':
176112156Smtm			buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
17728021Sjoerg			if (buf == 0)
17828021Sjoerg				return 0;
17928021Sjoerg			break;
18028019Sjoerg
18128021Sjoerg		case 'T':
182112156Smtm			buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
18328021Sjoerg			if (buf == 0)
18428021Sjoerg				return 0;
18528021Sjoerg			break;
18628019Sjoerg
18728021Sjoerg		case 'X':
188112156Smtm			buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
18928021Sjoerg			if (buf == 0)
19028021Sjoerg				return 0;
19128021Sjoerg			break;
19228019Sjoerg
19328021Sjoerg		case 'x':
194112156Smtm			buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
19528021Sjoerg			if (buf == 0)
19628021Sjoerg				return 0;
19728021Sjoerg			break;
19828019Sjoerg
19928021Sjoerg		case 'j':
20028164Sache			if (!isdigit((unsigned char)*buf))
20128021Sjoerg				return 0;
20228019Sjoerg
20354316Ssheldonh			len = 3;
20454316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
20528021Sjoerg				i *= 10;
20628021Sjoerg				i += *buf - '0';
20754316Ssheldonh				len--;
20828021Sjoerg			}
20953083Ssheldonh			if (i < 1 || i > 366)
21028021Sjoerg				return 0;
21128019Sjoerg
21253083Ssheldonh			tm->tm_yday = i - 1;
21328021Sjoerg			break;
21428019Sjoerg
21528021Sjoerg		case 'M':
21628021Sjoerg		case 'S':
21728164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
21828021Sjoerg				break;
21928019Sjoerg
22028164Sache			if (!isdigit((unsigned char)*buf))
22128021Sjoerg				return 0;
22228019Sjoerg
22354316Ssheldonh			len = 2;
22454316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
22528021Sjoerg				i *= 10;
22628021Sjoerg				i += *buf - '0';
22754316Ssheldonh				len--;
22828021Sjoerg			}
22928019Sjoerg
23053083Ssheldonh			if (c == 'M') {
23153083Ssheldonh				if (i > 59)
23253083Ssheldonh					return 0;
23328021Sjoerg				tm->tm_min = i;
23453083Ssheldonh			} else {
23553083Ssheldonh				if (i > 60)
23653083Ssheldonh					return 0;
23728021Sjoerg				tm->tm_sec = i;
23853083Ssheldonh			}
23928019Sjoerg
24028164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
24128164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
24228021Sjoerg					ptr++;
24328021Sjoerg			break;
24428019Sjoerg
24528021Sjoerg		case 'H':
24628021Sjoerg		case 'I':
24728021Sjoerg		case 'k':
24828021Sjoerg		case 'l':
24954316Ssheldonh			/*
25054316Ssheldonh			 * Of these, %l is the only specifier explicitly
25154316Ssheldonh			 * documented as not being zero-padded.  However,
25254316Ssheldonh			 * there is no harm in allowing zero-padding.
25354316Ssheldonh			 *
25454316Ssheldonh			 * XXX The %l specifier may gobble one too many
25554316Ssheldonh			 * digits if used incorrectly.
25654316Ssheldonh			 */
25728164Sache			if (!isdigit((unsigned char)*buf))
25828021Sjoerg				return 0;
25928019Sjoerg
26054316Ssheldonh			len = 2;
26154316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
26228021Sjoerg				i *= 10;
26328021Sjoerg				i += *buf - '0';
26454316Ssheldonh				len--;
26528021Sjoerg			}
26628021Sjoerg			if (c == 'H' || c == 'k') {
26728021Sjoerg				if (i > 23)
26828021Sjoerg					return 0;
26954301Ssheldonh			} else if (i > 12)
27028021Sjoerg				return 0;
27128019Sjoerg
27228021Sjoerg			tm->tm_hour = i;
27328019Sjoerg
27428164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
27528164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
27628021Sjoerg					ptr++;
27728021Sjoerg			break;
27828019Sjoerg
27928021Sjoerg		case 'p':
28054316Ssheldonh			/*
28154316Ssheldonh			 * XXX This is bogus if parsed before hour-related
28254316Ssheldonh			 * specifiers.
28354316Ssheldonh			 */
28472168Sphantom			len = strlen(tptr->am);
28572168Sphantom			if (strncasecmp(buf, tptr->am, len) == 0) {
28628021Sjoerg				if (tm->tm_hour > 12)
28728021Sjoerg					return 0;
28828021Sjoerg				if (tm->tm_hour == 12)
28928021Sjoerg					tm->tm_hour = 0;
29028021Sjoerg				buf += len;
29128021Sjoerg				break;
29228021Sjoerg			}
29328019Sjoerg
29472168Sphantom			len = strlen(tptr->pm);
29572168Sphantom			if (strncasecmp(buf, tptr->pm, len) == 0) {
29628021Sjoerg				if (tm->tm_hour > 12)
29728021Sjoerg					return 0;
29828021Sjoerg				if (tm->tm_hour != 12)
29928021Sjoerg					tm->tm_hour += 12;
30028021Sjoerg				buf += len;
30128021Sjoerg				break;
30228021Sjoerg			}
30328019Sjoerg
30428021Sjoerg			return 0;
30528019Sjoerg
30628021Sjoerg		case 'A':
30728021Sjoerg		case 'a':
30872168Sphantom			for (i = 0; i < asizeof(tptr->weekday); i++) {
30974409Sache				len = strlen(tptr->weekday[i]);
31074409Sache				if (strncasecmp(buf, tptr->weekday[i],
31174409Sache						len) == 0)
31274409Sache					break;
31374409Sache				len = strlen(tptr->wday[i]);
31474409Sache				if (strncasecmp(buf, tptr->wday[i],
31574409Sache						len) == 0)
31674409Sache					break;
31728021Sjoerg			}
31872168Sphantom			if (i == asizeof(tptr->weekday))
31928021Sjoerg				return 0;
32028019Sjoerg
32128021Sjoerg			tm->tm_wday = i;
32228021Sjoerg			buf += len;
32328021Sjoerg			break;
32428019Sjoerg
32553083Ssheldonh		case 'U':
32653083Ssheldonh		case 'W':
32753083Ssheldonh			/*
32853083Ssheldonh			 * XXX This is bogus, as we can not assume any valid
32953083Ssheldonh			 * information present in the tm structure at this
33053083Ssheldonh			 * point to calculate a real value, so just check the
33153083Ssheldonh			 * range for now.
33253083Ssheldonh			 */
33353083Ssheldonh			if (!isdigit((unsigned char)*buf))
33453083Ssheldonh				return 0;
33553083Ssheldonh
33654316Ssheldonh			len = 2;
33754316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
33853083Ssheldonh				i *= 10;
33953083Ssheldonh				i += *buf - '0';
34054316Ssheldonh				len--;
34153083Ssheldonh			}
34253083Ssheldonh			if (i > 53)
34353083Ssheldonh				return 0;
34453083Ssheldonh
34553083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
34653083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
34753083Ssheldonh					ptr++;
34853083Ssheldonh			break;
34953083Ssheldonh
35053083Ssheldonh		case 'w':
35153083Ssheldonh			if (!isdigit((unsigned char)*buf))
35253083Ssheldonh				return 0;
35353083Ssheldonh
35454316Ssheldonh			i = *buf - '0';
35553083Ssheldonh			if (i > 6)
35653083Ssheldonh				return 0;
35753083Ssheldonh
35853083Ssheldonh			tm->tm_wday = i;
35953083Ssheldonh
36053083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
36153083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
36253083Ssheldonh					ptr++;
36353083Ssheldonh			break;
36453083Ssheldonh
36528021Sjoerg		case 'd':
36628021Sjoerg		case 'e':
36754316Ssheldonh			/*
36854316Ssheldonh			 * The %e specifier is explicitly documented as not
36954316Ssheldonh			 * being zero-padded but there is no harm in allowing
37054316Ssheldonh			 * such padding.
37154316Ssheldonh			 *
37254316Ssheldonh			 * XXX The %e specifier may gobble one too many
37354316Ssheldonh			 * digits if used incorrectly.
37454316Ssheldonh			 */
37528164Sache			if (!isdigit((unsigned char)*buf))
37628021Sjoerg				return 0;
37728019Sjoerg
37854316Ssheldonh			len = 2;
37954316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
38028021Sjoerg				i *= 10;
38128021Sjoerg				i += *buf - '0';
38254316Ssheldonh				len--;
38328021Sjoerg			}
38428021Sjoerg			if (i > 31)
38528021Sjoerg				return 0;
38628019Sjoerg
38728021Sjoerg			tm->tm_mday = i;
38828019Sjoerg
38928164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
39028164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
39128021Sjoerg					ptr++;
39228021Sjoerg			break;
39328019Sjoerg
39428021Sjoerg		case 'B':
39528021Sjoerg		case 'b':
39628021Sjoerg		case 'h':
39772168Sphantom			for (i = 0; i < asizeof(tptr->month); i++) {
39853941Sache				if (Oalternative) {
39953941Sache					if (c == 'B') {
40072168Sphantom						len = strlen(tptr->alt_month[i]);
40153941Sache						if (strncasecmp(buf,
40272168Sphantom								tptr->alt_month[i],
40353941Sache								len) == 0)
40453941Sache							break;
40553941Sache					}
40653941Sache				} else {
40774409Sache					len = strlen(tptr->month[i]);
40874409Sache					if (strncasecmp(buf, tptr->month[i],
40974409Sache							len) == 0)
41074409Sache						break;
411207830Sedwin				}
412207830Sedwin			}
413207830Sedwin			/*
414207830Sedwin			 * Try the abbreviated month name if the full name
415207830Sedwin			 * wasn't found and Oalternative was not requested.
416207830Sedwin			 */
417207830Sedwin			if (i == asizeof(tptr->month) && !Oalternative) {
418207830Sedwin				for (i = 0; i < asizeof(tptr->month); i++) {
41974409Sache					len = strlen(tptr->mon[i]);
42074409Sache					if (strncasecmp(buf, tptr->mon[i],
42174409Sache							len) == 0)
42274409Sache						break;
42353941Sache				}
42428021Sjoerg			}
42572168Sphantom			if (i == asizeof(tptr->month))
42628021Sjoerg				return 0;
42728019Sjoerg
42828021Sjoerg			tm->tm_mon = i;
42928021Sjoerg			buf += len;
43028021Sjoerg			break;
43128019Sjoerg
43228021Sjoerg		case 'm':
43328164Sache			if (!isdigit((unsigned char)*buf))
43428021Sjoerg				return 0;
43528019Sjoerg
43654316Ssheldonh			len = 2;
43754316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
43828021Sjoerg				i *= 10;
43928021Sjoerg				i += *buf - '0';
44054316Ssheldonh				len--;
44128021Sjoerg			}
44228021Sjoerg			if (i < 1 || i > 12)
44328021Sjoerg				return 0;
44428019Sjoerg
44528021Sjoerg			tm->tm_mon = i - 1;
44628019Sjoerg
44728164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
44828164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
44928021Sjoerg					ptr++;
45028021Sjoerg			break;
45128019Sjoerg
45279664Sdd		case 's':
45379664Sdd			{
45479664Sdd			char *cp;
455122830Snectar			int sverrno;
456122830Snectar			long n;
45779664Sdd			time_t t;
45879664Sdd
459122830Snectar			sverrno = errno;
460122830Snectar			errno = 0;
461122830Snectar			n = strtol(buf, &cp, 10);
462122830Snectar			if (errno == ERANGE || (long)(t = n) != n) {
463122830Snectar				errno = sverrno;
46479664Sdd				return 0;
465122830Snectar			}
466122830Snectar			errno = sverrno;
46779664Sdd			buf = cp;
46879664Sdd			gmtime_r(&t, tm);
469112156Smtm			*GMTp = 1;
47079664Sdd			}
47179664Sdd			break;
47279664Sdd
47328021Sjoerg		case 'Y':
47428021Sjoerg		case 'y':
47528164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
47628021Sjoerg				break;
47728019Sjoerg
47828164Sache			if (!isdigit((unsigned char)*buf))
47928021Sjoerg				return 0;
48028019Sjoerg
48154316Ssheldonh			len = (c == 'Y') ? 4 : 2;
48254316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
48328021Sjoerg				i *= 10;
48428021Sjoerg				i += *buf - '0';
48554316Ssheldonh				len--;
48628021Sjoerg			}
48728021Sjoerg			if (c == 'Y')
48828021Sjoerg				i -= 1900;
48946051Swes			if (c == 'y' && i < 69)
49046042Swes				i += 100;
49128021Sjoerg			if (i < 0)
49228021Sjoerg				return 0;
49328019Sjoerg
49428021Sjoerg			tm->tm_year = i;
49528019Sjoerg
49628164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
49728164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
49828021Sjoerg					ptr++;
49928021Sjoerg			break;
50048550Sobrien
50148550Sobrien		case 'Z':
50248550Sobrien			{
50348550Sobrien			const char *cp;
50448550Sobrien			char *zonestr;
50548550Sobrien
50652860Sache			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
50748550Sobrien			if (cp - buf) {
50848550Sobrien				zonestr = alloca(cp - buf + 1);
50948550Sobrien				strncpy(zonestr, buf, cp - buf);
51048550Sobrien				zonestr[cp - buf] = '\0';
51148550Sobrien				tzset();
51248550Sobrien				if (0 == strcmp(zonestr, "GMT")) {
513112156Smtm				    *GMTp = 1;
51448550Sobrien				} else if (0 == strcmp(zonestr, tzname[0])) {
51548614Sobrien				    tm->tm_isdst = 0;
51648550Sobrien				} else if (0 == strcmp(zonestr, tzname[1])) {
51748614Sobrien				    tm->tm_isdst = 1;
51848550Sobrien				} else {
51948614Sobrien				    return 0;
52048550Sobrien				}
52148550Sobrien				buf += cp - buf;
52248550Sobrien			}
52348550Sobrien			}
52448550Sobrien			break;
525195015Sdelphij
526195015Sdelphij		case 'z':
527195015Sdelphij			{
528195015Sdelphij			int sign = 1;
529195015Sdelphij
530195015Sdelphij			if (*buf != '+') {
531195015Sdelphij				if (*buf == '-')
532195015Sdelphij					sign = -1;
533195015Sdelphij				else
534195015Sdelphij					return 0;
535195015Sdelphij			}
536195015Sdelphij
537195015Sdelphij			buf++;
538195015Sdelphij			i = 0;
539195015Sdelphij			for (len = 4; len > 0; len--) {
540196752Sache				if (isdigit((unsigned char)*buf)) {
541195015Sdelphij					i *= 10;
542195015Sdelphij					i += *buf - '0';
543195015Sdelphij					buf++;
544195015Sdelphij				} else
545195015Sdelphij					return 0;
546195015Sdelphij			}
547195015Sdelphij
548195015Sdelphij			tm->tm_hour -= sign * (i / 100);
549195015Sdelphij			tm->tm_min  -= sign * (i % 100);
550195015Sdelphij			*GMTp = 1;
551195015Sdelphij			}
552195015Sdelphij			break;
55328021Sjoerg		}
55428021Sjoerg	}
55548614Sobrien	return (char *)buf;
55648614Sobrien}
55728019Sjoerg
55848614Sobrien
55948614Sobrienchar *
560103012Stjrstrptime(const char * __restrict buf, const char * __restrict fmt,
561103012Stjr    struct tm * __restrict tm)
56248614Sobrien{
56348614Sobrien	char *ret;
564112156Smtm	int gmt;
56548614Sobrien
566112156Smtm	gmt = 0;
567112156Smtm	ret = _strptime(buf, fmt, tm, &gmt);
568114285Smtm	if (ret && gmt) {
569114285Smtm		time_t t = timegm(tm);
57071579Sdeischen		localtime_r(&t, tm);
57148550Sobrien	}
57248614Sobrien
573112156Smtm	return (ret);
57428019Sjoerg}
575