strptime.c revision 74412
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
5428021Sjoerg#ifdef LIBC_RCS
5528021Sjoergstatic const char rcsid[] =
5650476Speter  "$FreeBSD: head/lib/libc/stdtime/strptime.c 74412 2001-03-18 11:58:15Z ache $";
5728021Sjoerg#endif
5828021Sjoerg
5928019Sjoerg#ifndef lint
6028021Sjoerg#ifndef NOID
6128019Sjoergstatic char copyright[] =
6228019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
6328021Sjoergstatic char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
6428021Sjoerg#endif /* !defined NOID */
6528019Sjoerg#endif /* not lint */
6628019Sjoerg
6771579Sdeischen#include "namespace.h"
6828019Sjoerg#include <time.h>
6928019Sjoerg#include <ctype.h>
7028019Sjoerg#include <string.h>
7148614Sobrien#include <pthread.h>
7271579Sdeischen#include "un-namespace.h"
7371579Sdeischen#include "libc_private.h"
7428021Sjoerg#include "timelocal.h"
7528019Sjoerg
7648614Sobrienstatic char * _strptime(const char *, const char *, struct tm *);
7748614Sobrien
7871579Sdeischenstatic pthread_mutex_t	gotgmt_mutex = PTHREAD_MUTEX_INITIALIZER;
7948614Sobrienstatic int got_GMT;
8048614Sobrien
8128021Sjoerg#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
8228019Sjoerg
8348614Sobrienstatic char *
8448614Sobrien_strptime(const char *buf, const char *fmt, struct tm *tm)
8528019Sjoerg{
8628021Sjoerg	char	c;
8728021Sjoerg	const char *ptr;
8828021Sjoerg	int	i,
8928021Sjoerg		len;
9053941Sache	int Ealternative, Oalternative;
9172168Sphantom	struct lc_time_T *tptr = __get_current_time_locale();
9228019Sjoerg
9328021Sjoerg	ptr = fmt;
9428021Sjoerg	while (*ptr != 0) {
9528021Sjoerg		if (*buf == 0)
9628021Sjoerg			break;
9728019Sjoerg
9828021Sjoerg		c = *ptr++;
9928019Sjoerg
10028021Sjoerg		if (c != '%') {
10128164Sache			if (isspace((unsigned char)c))
10228164Sache				while (*buf != 0 && isspace((unsigned char)*buf))
10328021Sjoerg					buf++;
10428021Sjoerg			else if (c != *buf++)
10528021Sjoerg				return 0;
10628021Sjoerg			continue;
10728021Sjoerg		}
10828019Sjoerg
10953941Sache		Ealternative = 0;
11053941Sache		Oalternative = 0;
11153941Sachelabel:
11228021Sjoerg		c = *ptr++;
11328021Sjoerg		switch (c) {
11428021Sjoerg		case 0:
11528021Sjoerg		case '%':
11628021Sjoerg			if (*buf++ != '%')
11728021Sjoerg				return 0;
11828021Sjoerg			break;
11928019Sjoerg
12053941Sache		case '+':
12172168Sphantom			buf = _strptime(buf, tptr->date_fmt, tm);
12228021Sjoerg			if (buf == 0)
12328021Sjoerg				return 0;
12428021Sjoerg			break;
12528019Sjoerg
12653941Sache		case 'C':
12753941Sache			if (!isdigit((unsigned char)*buf))
12853941Sache				return 0;
12953941Sache
13054316Ssheldonh			/* XXX This will break for 3-digit centuries. */
13154316Ssheldonh			len = 2;
13254316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
13353941Sache				i *= 10;
13453941Sache				i += *buf - '0';
13554316Ssheldonh				len--;
13653941Sache			}
13753941Sache			if (i < 19)
13853941Sache				return 0;
13953941Sache
14053941Sache			tm->tm_year = i * 100 - 1900;
14153941Sache			break;
14253941Sache
14328021Sjoerg		case 'c':
14472183Sache			buf = _strptime(buf, tptr->c_fmt, tm);
14528021Sjoerg			if (buf == 0)
14628021Sjoerg				return 0;
14728021Sjoerg			break;
14828019Sjoerg
14928021Sjoerg		case 'D':
15048614Sobrien			buf = _strptime(buf, "%m/%d/%y", tm);
15128021Sjoerg			if (buf == 0)
15228021Sjoerg				return 0;
15328021Sjoerg			break;
15428019Sjoerg
15553941Sache		case 'E':
15653960Sache			if (Ealternative || Oalternative)
15753960Sache				break;
15853941Sache			Ealternative++;
15953941Sache			goto label;
16053941Sache
16153941Sache		case 'O':
16253960Sache			if (Ealternative || Oalternative)
16353960Sache				break;
16453941Sache			Oalternative++;
16553941Sache			goto label;
16653941Sache
16753960Sache		case 'F':
16874412Sache			if (!Ealternative)
16974412Sache				buf = _strptime(buf, "%Y-%m-%d", tm);
17074412Sache			else
17174412Sache				buf = _strptime(buf,
17274412Sache						*(tptr->md_order) == 'd' ?
17374412Sache						"%e %B" : "%B %e", tm);
17474412Sache			if (buf == 0)
17574412Sache				return 0;
17674412Sache			break;
17774412Sache
17853960Sache		case 'f':
17953960Sache			if (!Ealternative)
18053960Sache				break;
18174412Sache			buf = _strptime(buf,
18274412Sache				 *(tptr->md_order) == 'd' ? "%e %b" : "%b %e",
18374412Sache				 tm);
18453960Sache			if (buf == 0)
18553960Sache				return 0;
18653960Sache			break;
18753960Sache
18828021Sjoerg		case 'R':
18948614Sobrien			buf = _strptime(buf, "%H:%M", tm);
19028021Sjoerg			if (buf == 0)
19128021Sjoerg				return 0;
19228021Sjoerg			break;
19328019Sjoerg
19428021Sjoerg		case 'r':
19573359Sache			buf = _strptime(buf, tptr->ampm_fmt, tm);
19628021Sjoerg			if (buf == 0)
19728021Sjoerg				return 0;
19828021Sjoerg			break;
19928019Sjoerg
20028021Sjoerg		case 'T':
20148614Sobrien			buf = _strptime(buf, "%H:%M:%S", tm);
20228021Sjoerg			if (buf == 0)
20328021Sjoerg				return 0;
20428021Sjoerg			break;
20528019Sjoerg
20628021Sjoerg		case 'X':
20772168Sphantom			buf = _strptime(buf, tptr->X_fmt, tm);
20828021Sjoerg			if (buf == 0)
20928021Sjoerg				return 0;
21028021Sjoerg			break;
21128019Sjoerg
21228021Sjoerg		case 'x':
21372168Sphantom			buf = _strptime(buf, tptr->x_fmt, tm);
21428021Sjoerg			if (buf == 0)
21528021Sjoerg				return 0;
21628021Sjoerg			break;
21728019Sjoerg
21828021Sjoerg		case 'j':
21928164Sache			if (!isdigit((unsigned char)*buf))
22028021Sjoerg				return 0;
22128019Sjoerg
22254316Ssheldonh			len = 3;
22354316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
22428021Sjoerg				i *= 10;
22528021Sjoerg				i += *buf - '0';
22654316Ssheldonh				len--;
22728021Sjoerg			}
22853083Ssheldonh			if (i < 1 || i > 366)
22928021Sjoerg				return 0;
23028019Sjoerg
23153083Ssheldonh			tm->tm_yday = i - 1;
23228021Sjoerg			break;
23328019Sjoerg
23428021Sjoerg		case 'M':
23528021Sjoerg		case 'S':
23628164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
23728021Sjoerg				break;
23828019Sjoerg
23928164Sache			if (!isdigit((unsigned char)*buf))
24028021Sjoerg				return 0;
24128019Sjoerg
24254316Ssheldonh			len = 2;
24354316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
24428021Sjoerg				i *= 10;
24528021Sjoerg				i += *buf - '0';
24654316Ssheldonh				len--;
24728021Sjoerg			}
24828019Sjoerg
24953083Ssheldonh			if (c == 'M') {
25053083Ssheldonh				if (i > 59)
25153083Ssheldonh					return 0;
25228021Sjoerg				tm->tm_min = i;
25353083Ssheldonh			} else {
25453083Ssheldonh				if (i > 60)
25553083Ssheldonh					return 0;
25628021Sjoerg				tm->tm_sec = i;
25753083Ssheldonh			}
25828019Sjoerg
25928164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
26028164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
26128021Sjoerg					ptr++;
26228021Sjoerg			break;
26328019Sjoerg
26428021Sjoerg		case 'H':
26528021Sjoerg		case 'I':
26628021Sjoerg		case 'k':
26728021Sjoerg		case 'l':
26854316Ssheldonh			/*
26954316Ssheldonh			 * Of these, %l is the only specifier explicitly
27054316Ssheldonh			 * documented as not being zero-padded.  However,
27154316Ssheldonh			 * there is no harm in allowing zero-padding.
27254316Ssheldonh			 *
27354316Ssheldonh			 * XXX The %l specifier may gobble one too many
27454316Ssheldonh			 * digits if used incorrectly.
27554316Ssheldonh			 */
27628164Sache			if (!isdigit((unsigned char)*buf))
27728021Sjoerg				return 0;
27828019Sjoerg
27954316Ssheldonh			len = 2;
28054316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
28128021Sjoerg				i *= 10;
28228021Sjoerg				i += *buf - '0';
28354316Ssheldonh				len--;
28428021Sjoerg			}
28528021Sjoerg			if (c == 'H' || c == 'k') {
28628021Sjoerg				if (i > 23)
28728021Sjoerg					return 0;
28854301Ssheldonh			} else if (i > 12)
28928021Sjoerg				return 0;
29028019Sjoerg
29128021Sjoerg			tm->tm_hour = i;
29228019Sjoerg
29328164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
29428164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
29528021Sjoerg					ptr++;
29628021Sjoerg			break;
29728019Sjoerg
29828021Sjoerg		case 'p':
29954316Ssheldonh			/*
30054316Ssheldonh			 * XXX This is bogus if parsed before hour-related
30154316Ssheldonh			 * specifiers.
30254316Ssheldonh			 */
30372168Sphantom			len = strlen(tptr->am);
30472168Sphantom			if (strncasecmp(buf, tptr->am, len) == 0) {
30528021Sjoerg				if (tm->tm_hour > 12)
30628021Sjoerg					return 0;
30728021Sjoerg				if (tm->tm_hour == 12)
30828021Sjoerg					tm->tm_hour = 0;
30928021Sjoerg				buf += len;
31028021Sjoerg				break;
31128021Sjoerg			}
31228019Sjoerg
31372168Sphantom			len = strlen(tptr->pm);
31472168Sphantom			if (strncasecmp(buf, tptr->pm, len) == 0) {
31528021Sjoerg				if (tm->tm_hour > 12)
31628021Sjoerg					return 0;
31728021Sjoerg				if (tm->tm_hour != 12)
31828021Sjoerg					tm->tm_hour += 12;
31928021Sjoerg				buf += len;
32028021Sjoerg				break;
32128021Sjoerg			}
32228019Sjoerg
32328021Sjoerg			return 0;
32428019Sjoerg
32528021Sjoerg		case 'A':
32628021Sjoerg		case 'a':
32772168Sphantom			for (i = 0; i < asizeof(tptr->weekday); i++) {
32874409Sache				len = strlen(tptr->weekday[i]);
32974409Sache				if (strncasecmp(buf, tptr->weekday[i],
33074409Sache						len) == 0)
33174409Sache					break;
33274409Sache				len = strlen(tptr->wday[i]);
33374409Sache				if (strncasecmp(buf, tptr->wday[i],
33474409Sache						len) == 0)
33574409Sache					break;
33628021Sjoerg			}
33772168Sphantom			if (i == asizeof(tptr->weekday))
33828021Sjoerg				return 0;
33928019Sjoerg
34028021Sjoerg			tm->tm_wday = i;
34128021Sjoerg			buf += len;
34228021Sjoerg			break;
34328019Sjoerg
34453083Ssheldonh		case 'U':
34553083Ssheldonh		case 'W':
34653083Ssheldonh			/*
34753083Ssheldonh			 * XXX This is bogus, as we can not assume any valid
34853083Ssheldonh			 * information present in the tm structure at this
34953083Ssheldonh			 * point to calculate a real value, so just check the
35053083Ssheldonh			 * range for now.
35153083Ssheldonh			 */
35253083Ssheldonh			if (!isdigit((unsigned char)*buf))
35353083Ssheldonh				return 0;
35453083Ssheldonh
35554316Ssheldonh			len = 2;
35654316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
35753083Ssheldonh				i *= 10;
35853083Ssheldonh				i += *buf - '0';
35954316Ssheldonh				len--;
36053083Ssheldonh			}
36153083Ssheldonh			if (i > 53)
36253083Ssheldonh				return 0;
36353083Ssheldonh
36453083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
36553083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
36653083Ssheldonh					ptr++;
36753083Ssheldonh			break;
36853083Ssheldonh
36953083Ssheldonh		case 'w':
37053083Ssheldonh			if (!isdigit((unsigned char)*buf))
37153083Ssheldonh				return 0;
37253083Ssheldonh
37354316Ssheldonh			i = *buf - '0';
37453083Ssheldonh			if (i > 6)
37553083Ssheldonh				return 0;
37653083Ssheldonh
37753083Ssheldonh			tm->tm_wday = i;
37853083Ssheldonh
37953083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
38053083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
38153083Ssheldonh					ptr++;
38253083Ssheldonh			break;
38353083Ssheldonh
38428021Sjoerg		case 'd':
38528021Sjoerg		case 'e':
38654316Ssheldonh			/*
38754316Ssheldonh			 * The %e specifier is explicitly documented as not
38854316Ssheldonh			 * being zero-padded but there is no harm in allowing
38954316Ssheldonh			 * such padding.
39054316Ssheldonh			 *
39154316Ssheldonh			 * XXX The %e specifier may gobble one too many
39254316Ssheldonh			 * digits if used incorrectly.
39354316Ssheldonh			 */
39428164Sache			if (!isdigit((unsigned char)*buf))
39528021Sjoerg				return 0;
39628019Sjoerg
39754316Ssheldonh			len = 2;
39854316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
39928021Sjoerg				i *= 10;
40028021Sjoerg				i += *buf - '0';
40154316Ssheldonh				len--;
40228021Sjoerg			}
40328021Sjoerg			if (i > 31)
40428021Sjoerg				return 0;
40528019Sjoerg
40628021Sjoerg			tm->tm_mday = i;
40728019Sjoerg
40828164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
40928164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
41028021Sjoerg					ptr++;
41128021Sjoerg			break;
41228019Sjoerg
41328021Sjoerg		case 'B':
41428021Sjoerg		case 'b':
41528021Sjoerg		case 'h':
41672168Sphantom			for (i = 0; i < asizeof(tptr->month); i++) {
41753941Sache				if (Oalternative) {
41853941Sache					if (c == 'B') {
41972168Sphantom						len = strlen(tptr->alt_month[i]);
42053941Sache						if (strncasecmp(buf,
42172168Sphantom								tptr->alt_month[i],
42253941Sache								len) == 0)
42353941Sache							break;
42453941Sache					}
42553941Sache				} else {
42674409Sache					len = strlen(tptr->month[i]);
42774409Sache					if (strncasecmp(buf, tptr->month[i],
42874409Sache							len) == 0)
42974409Sache						break;
43074409Sache					len = strlen(tptr->mon[i]);
43174409Sache					if (strncasecmp(buf, tptr->mon[i],
43274409Sache							len) == 0)
43374409Sache						break;
43453941Sache				}
43528021Sjoerg			}
43672168Sphantom			if (i == asizeof(tptr->month))
43728021Sjoerg				return 0;
43828019Sjoerg
43928021Sjoerg			tm->tm_mon = i;
44028021Sjoerg			buf += len;
44128021Sjoerg			break;
44228019Sjoerg
44328021Sjoerg		case 'm':
44428164Sache			if (!isdigit((unsigned char)*buf))
44528021Sjoerg				return 0;
44628019Sjoerg
44754316Ssheldonh			len = 2;
44854316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
44928021Sjoerg				i *= 10;
45028021Sjoerg				i += *buf - '0';
45154316Ssheldonh				len--;
45228021Sjoerg			}
45328021Sjoerg			if (i < 1 || i > 12)
45428021Sjoerg				return 0;
45528019Sjoerg
45628021Sjoerg			tm->tm_mon = i - 1;
45728019Sjoerg
45828164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
45928164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
46028021Sjoerg					ptr++;
46128021Sjoerg			break;
46228019Sjoerg
46328021Sjoerg		case 'Y':
46428021Sjoerg		case 'y':
46528164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
46628021Sjoerg				break;
46728019Sjoerg
46828164Sache			if (!isdigit((unsigned char)*buf))
46928021Sjoerg				return 0;
47028019Sjoerg
47154316Ssheldonh			len = (c == 'Y') ? 4 : 2;
47254316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
47328021Sjoerg				i *= 10;
47428021Sjoerg				i += *buf - '0';
47554316Ssheldonh				len--;
47628021Sjoerg			}
47728021Sjoerg			if (c == 'Y')
47828021Sjoerg				i -= 1900;
47946051Swes			if (c == 'y' && i < 69)
48046042Swes				i += 100;
48128021Sjoerg			if (i < 0)
48228021Sjoerg				return 0;
48328019Sjoerg
48428021Sjoerg			tm->tm_year = i;
48528019Sjoerg
48628164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
48728164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
48828021Sjoerg					ptr++;
48928021Sjoerg			break;
49048550Sobrien
49148550Sobrien		case 'Z':
49248550Sobrien			{
49348550Sobrien			const char *cp;
49448550Sobrien			char *zonestr;
49548550Sobrien
49652860Sache			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
49748550Sobrien			if (cp - buf) {
49848550Sobrien				zonestr = alloca(cp - buf + 1);
49948550Sobrien				strncpy(zonestr, buf, cp - buf);
50048550Sobrien				zonestr[cp - buf] = '\0';
50148550Sobrien				tzset();
50248550Sobrien				if (0 == strcmp(zonestr, "GMT")) {
50348614Sobrien				    got_GMT = 1;
50448550Sobrien				} else if (0 == strcmp(zonestr, tzname[0])) {
50548614Sobrien				    tm->tm_isdst = 0;
50648550Sobrien				} else if (0 == strcmp(zonestr, tzname[1])) {
50748614Sobrien				    tm->tm_isdst = 1;
50848550Sobrien				} else {
50948614Sobrien				    return 0;
51048550Sobrien				}
51148550Sobrien				buf += cp - buf;
51248550Sobrien			}
51348550Sobrien			}
51448550Sobrien			break;
51528021Sjoerg		}
51628021Sjoerg	}
51748614Sobrien	return (char *)buf;
51848614Sobrien}
51928019Sjoerg
52048614Sobrien
52148614Sobrienchar *
52248614Sobrienstrptime(const char *buf, const char *fmt, struct tm *tm)
52348614Sobrien{
52448614Sobrien	char *ret;
52548614Sobrien
52671579Sdeischen	if (__isthreaded)
52771579Sdeischen		_pthread_mutex_lock(&gotgmt_mutex);
52848614Sobrien
52948614Sobrien	got_GMT = 0;
53048614Sobrien	ret = _strptime(buf, fmt, tm);
53148614Sobrien	if (ret && got_GMT) {
53248550Sobrien		time_t t = timegm(tm);
53371579Sdeischen		localtime_r(&t, tm);
53448614Sobrien		got_GMT = 0;
53548550Sobrien	}
53648614Sobrien
53771579Sdeischen	if (__isthreaded)
53871579Sdeischen		_pthread_mutex_unlock(&gotgmt_mutex);
53948614Sobrien
54048614Sobrien	return ret;
54128019Sjoerg}
542