strptime.c revision 122830
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 122830 2003-11-17 04:19:15Z nectar $");
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;
41174409Sache					len = strlen(tptr->mon[i]);
41274409Sache					if (strncasecmp(buf, tptr->mon[i],
41374409Sache							len) == 0)
41474409Sache						break;
41553941Sache				}
41628021Sjoerg			}
41772168Sphantom			if (i == asizeof(tptr->month))
41828021Sjoerg				return 0;
41928019Sjoerg
42028021Sjoerg			tm->tm_mon = i;
42128021Sjoerg			buf += len;
42228021Sjoerg			break;
42328019Sjoerg
42428021Sjoerg		case 'm':
42528164Sache			if (!isdigit((unsigned char)*buf))
42628021Sjoerg				return 0;
42728019Sjoerg
42854316Ssheldonh			len = 2;
42954316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
43028021Sjoerg				i *= 10;
43128021Sjoerg				i += *buf - '0';
43254316Ssheldonh				len--;
43328021Sjoerg			}
43428021Sjoerg			if (i < 1 || i > 12)
43528021Sjoerg				return 0;
43628019Sjoerg
43728021Sjoerg			tm->tm_mon = i - 1;
43828019Sjoerg
43928164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
44028164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
44128021Sjoerg					ptr++;
44228021Sjoerg			break;
44328019Sjoerg
44479664Sdd		case 's':
44579664Sdd			{
44679664Sdd			char *cp;
447122830Snectar			int sverrno;
448122830Snectar			long n;
44979664Sdd			time_t t;
45079664Sdd
451122830Snectar			sverrno = errno;
452122830Snectar			errno = 0;
453122830Snectar			n = strtol(buf, &cp, 10);
454122830Snectar			if (errno == ERANGE || (long)(t = n) != n) {
455122830Snectar				errno = sverrno;
45679664Sdd				return 0;
457122830Snectar			}
458122830Snectar			errno = sverrno;
45979664Sdd			buf = cp;
46079664Sdd			gmtime_r(&t, tm);
461112156Smtm			*GMTp = 1;
46279664Sdd			}
46379664Sdd			break;
46479664Sdd
46528021Sjoerg		case 'Y':
46628021Sjoerg		case 'y':
46728164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
46828021Sjoerg				break;
46928019Sjoerg
47028164Sache			if (!isdigit((unsigned char)*buf))
47128021Sjoerg				return 0;
47228019Sjoerg
47354316Ssheldonh			len = (c == 'Y') ? 4 : 2;
47454316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
47528021Sjoerg				i *= 10;
47628021Sjoerg				i += *buf - '0';
47754316Ssheldonh				len--;
47828021Sjoerg			}
47928021Sjoerg			if (c == 'Y')
48028021Sjoerg				i -= 1900;
48146051Swes			if (c == 'y' && i < 69)
48246042Swes				i += 100;
48328021Sjoerg			if (i < 0)
48428021Sjoerg				return 0;
48528019Sjoerg
48628021Sjoerg			tm->tm_year = i;
48728019Sjoerg
48828164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
48928164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
49028021Sjoerg					ptr++;
49128021Sjoerg			break;
49248550Sobrien
49348550Sobrien		case 'Z':
49448550Sobrien			{
49548550Sobrien			const char *cp;
49648550Sobrien			char *zonestr;
49748550Sobrien
49852860Sache			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
49948550Sobrien			if (cp - buf) {
50048550Sobrien				zonestr = alloca(cp - buf + 1);
50148550Sobrien				strncpy(zonestr, buf, cp - buf);
50248550Sobrien				zonestr[cp - buf] = '\0';
50348550Sobrien				tzset();
50448550Sobrien				if (0 == strcmp(zonestr, "GMT")) {
505112156Smtm				    *GMTp = 1;
50648550Sobrien				} else if (0 == strcmp(zonestr, tzname[0])) {
50748614Sobrien				    tm->tm_isdst = 0;
50848550Sobrien				} else if (0 == strcmp(zonestr, tzname[1])) {
50948614Sobrien				    tm->tm_isdst = 1;
51048550Sobrien				} else {
51148614Sobrien				    return 0;
51248550Sobrien				}
51348550Sobrien				buf += cp - buf;
51448550Sobrien			}
51548550Sobrien			}
51648550Sobrien			break;
51728021Sjoerg		}
51828021Sjoerg	}
51948614Sobrien	return (char *)buf;
52048614Sobrien}
52128019Sjoerg
52248614Sobrien
52348614Sobrienchar *
524103012Stjrstrptime(const char * __restrict buf, const char * __restrict fmt,
525103012Stjr    struct tm * __restrict tm)
52648614Sobrien{
52748614Sobrien	char *ret;
528112156Smtm	int gmt;
52948614Sobrien
530112156Smtm	gmt = 0;
531112156Smtm	ret = _strptime(buf, fmt, tm, &gmt);
532114285Smtm	if (ret && gmt) {
533114285Smtm		time_t t = timegm(tm);
53471579Sdeischen		localtime_r(&t, tm);
53548550Sobrien	}
53648614Sobrien
537112156Smtm	return (ret);
53828019Sjoerg}
539