changeset 13249:abc9578d5a0e

317 strptime needs %Z support Reviewed by: richlowe@richlowe.net Reviewed by: lvskiprof@cox.net Reviewed by: gwr@nexenta.com Approved by: richlowe@richlowe.net
author Garrett D'Amore <garrett@nexenta.com>
date Sat, 04 Dec 2010 17:33:07 -0800
parents ed4997a098c7
children 34250eb8d616
files usr/src/head/time.h usr/src/lib/libc/port/gen/localtime.c usr/src/lib/libc/port/locale/strftime.c usr/src/lib/libc/port/locale/strptime.c usr/src/lib/libc/port/mapfile-vers
diffstat 5 files changed, 277 insertions(+), 196 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/head/time.h	Fri Dec 03 07:32:02 2010 -0800
+++ b/usr/src/head/time.h	Sat Dec 04 17:33:07 2010 -0800
@@ -26,12 +26,13 @@
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2010 Nexenta Systems, Inc.  Al rights reserved.
+ */
 
 #ifndef _TIME_H
 #define	_TIME_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.18 */
-
 #include <sys/feature_tests.h>
 #include <iso/time_iso.h>
 #if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
@@ -177,6 +178,7 @@
 
 #if (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
 	defined(__EXTENSIONS__)
+extern time_t timegm(struct tm *);
 extern int cftime(char *, char *, const time_t *);
 extern int ascftime(char *, const char *, const struct tm *);
 extern long altzone;
@@ -198,6 +200,7 @@
 
 extern int cftime(), ascftime();
 extern void tzset();
+extern time_t timegm();
 
 #ifdef _STRPTIME_DONTZERO
 #ifdef __PRAGMA_REDEFINE_EXTNAME
--- a/usr/src/lib/libc/port/gen/localtime.c	Fri Dec 03 07:32:02 2010 -0800
+++ b/usr/src/lib/libc/port/gen/localtime.c	Sat Dec 04 17:33:07 2010 -0800
@@ -20,6 +20,10 @@
  */
 
 /*
+ * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+/*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -673,8 +677,8 @@
  * normalized time_t, also inducing documented side-effects in
  * extern global zone state variables.  (See mktime(3C)).
  */
-time_t
-mktime(struct tm *tmptr)
+static time_t
+mktime1(struct tm *tmptr, int usetz)
 {
 	struct tm _tm;
 	long long t;		/* must hold more than 32-bit time_t */
@@ -722,74 +726,93 @@
 	else
 		t += SECSPERDAY * __yday_to_month[tmptr->tm_mon];
 
-	unused = ltzset_u((time_t)t);
 
-	/* Attempt to convert time to GMT based on tm_isdst setting */
-	t += (tmptr->tm_isdst > 0) ? altzone : timezone;
+	if (usetz) {
+		/*
+		 * If called from mktime(), then we need to do the TZ
+		 * related transformations.
+		 */
+
+		unused = ltzset_u((time_t)t);
+
+		/* Attempt to convert time to GMT based on tm_isdst setting */
+		t += (tmptr->tm_isdst > 0) ? altzone : timezone;
 
 #ifdef _ILP32
-	overflow = t > LONG_MAX || t < LONG_MIN ||
-	    tmptr->tm_year < 1 || tmptr->tm_year > 138;
+		overflow = t > LONG_MAX || t < LONG_MIN ||
+		    tmptr->tm_year < 1 || tmptr->tm_year > 138;
 #else
-	overflow = t > LONG_MAX || t < LONG_MIN;
+		overflow = t > LONG_MAX || t < LONG_MIN;
 #endif
-	set_zone_context((time_t)t);
-	if (tmptr->tm_isdst < 0) {
-		long dst_delta = timezone - altzone;
-		switch (curr_zonerules) {
-		case ZONEINFO:
-			if (is_in_dst) {
-				t -= dst_delta;
-				set_zone_context((time_t)t);
+		set_zone_context((time_t)t);
+		if (tmptr->tm_isdst < 0) {
+			long dst_delta = timezone - altzone;
+			switch (curr_zonerules) {
+			case ZONEINFO:
 				if (is_in_dst) {
-					(void) offtime_u((time_t)t,
-					    -altzone, &_tm);
-					_tm.tm_isdst = 1;
+					t -= dst_delta;
+					set_zone_context((time_t)t);
+					if (is_in_dst) {
+						(void) offtime_u((time_t)t,
+						    -altzone, &_tm);
+						_tm.tm_isdst = 1;
+					} else {
+						(void) offtime_u((time_t)t,
+						    -timezone, &_tm);
+					}
 				} else {
-					(void) offtime_u((time_t)t,
-					    -timezone, &_tm);
+					(void) offtime_u((time_t)t, -timezone,
+					    &_tm);
 				}
-			} else {
-				(void) offtime_u((time_t)t, -timezone, &_tm);
-			}
-			break;
-		case POSIX_USA:
-		case POSIX:
-			if (is_in_dst) {
-				t -= dst_delta;
-				set_zone_context((time_t)t);
+				break;
+			case POSIX_USA:
+			case POSIX:
 				if (is_in_dst) {
-					(void) offtime_u((time_t)t,
-					    -altzone, &_tm);
-					_tm.tm_isdst = 1;
-				} else {
-					(void) offtime_u((time_t)t,
-					    -timezone, &_tm);
-				}
-			} else { /* check for ambiguous 'fallback' transition */
-				set_zone_context((time_t)t - dst_delta);
-				if (is_in_dst) {  /* In fallback, force DST */
 					t -= dst_delta;
-					(void) offtime_u((time_t)t,
-					    -altzone, &_tm);
-					_tm.tm_isdst = 1;
+					set_zone_context((time_t)t);
+					if (is_in_dst) {
+						(void) offtime_u((time_t)t,
+						    -altzone, &_tm);
+						_tm.tm_isdst = 1;
+					} else {
+						(void) offtime_u((time_t)t,
+						    -timezone, &_tm);
+					}
 				} else {
-					(void) offtime_u((time_t)t,
-					    -timezone, &_tm);
+					/*
+					 * check for ambiguous
+					 * 'fallback' transition
+					 */
+					set_zone_context((time_t)t - dst_delta);
+					if (is_in_dst) {
+						/* In fallback, force DST */
+						t -= dst_delta;
+						(void) offtime_u((time_t)t,
+						    -altzone, &_tm);
+						_tm.tm_isdst = 1;
+					} else {
+						(void) offtime_u((time_t)t,
+						    -timezone, &_tm);
+					}
 				}
-			}
-			break;
+				break;
 
-		case ZONERULES_INVALID:
-			(void) offtime_u((time_t)t, 0L, &_tm);
-			break;
+			case ZONERULES_INVALID:
+				(void) offtime_u((time_t)t, 0L, &_tm);
+				break;
 
+			}
+		} else if (is_in_dst) {
+			(void) offtime_u((time_t)t, -altzone, &_tm);
+			_tm.tm_isdst = 1;
+		} else {
+			(void) offtime_u((time_t)t, -timezone, &_tm);
 		}
-	} else if (is_in_dst) {
-		(void) offtime_u((time_t)t, -altzone, &_tm);
-		_tm.tm_isdst = 1;
-	} else {
-		(void) offtime_u((time_t)t, -timezone, &_tm);
+
+	} else {	/* !usetz, i.e. using UTC */
+		overflow = 0;
+		/* Normalize the TM structure */
+		(void) offtime_u((time_t)t, 0, &_tm);
 	}
 
 	if (overflow || t > LONG_MAX || t < LONG_MIN) {
@@ -807,6 +830,19 @@
 	return ((time_t)t);
 }
 
+time_t
+mktime(struct tm *tmptr)
+{
+	return (mktime1(tmptr, TRUE));
+}
+
+time_t
+timegm(struct tm *tmptr)
+{
+	return (mktime1(tmptr, FALSE));
+}
+
+
 /*
  * Sets extern global zone state variables based on the current
  * time.  Specifically, tzname[], timezone, altzone, and daylight
--- a/usr/src/lib/libc/port/locale/strftime.c	Fri Dec 03 07:32:02 2010 -0800
+++ b/usr/src/lib/libc/port/locale/strftime.c	Sat Dec 04 17:33:07 2010 -0800
@@ -233,12 +233,16 @@
 				    pt, ptlim);
 				continue;
 
-			/*
-			 * Note: 's' for seconds since epoch was removed.
-			 * While FreeBSD and Linux appear to support this,
-			 * Sun Solaris does not.  Furthermore, the FreeBSD
-			 * implementation was not correct for _LP64.
-			 */
+			case 's':
+			{
+				struct tm tm;
+				char *buf;
+
+				tm = *t;
+				(void) asprintf(&buf, "%ld", mktime(&tm));
+				pt = _add(buf, pt, ptlim);
+				continue;
+			}
 
 			case 'T':
 				pt = _fmt("%H:%M:%S", t, pt, ptlim);
--- a/usr/src/lib/libc/port/locale/strptime.c	Fri Dec 03 07:32:02 2010 -0800
+++ b/usr/src/lib/libc/port/locale/strptime.c	Sat Dec 04 17:33:07 2010 -0800
@@ -43,15 +43,27 @@
 
 #define	asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
 
+#define	F_GMT		(1 << 0)
+#define	F_ZERO		(1 << 1)
+#define	F_RECURSE	(1 << 2)
+
 static char *
-__strptime(const char *buf, const char *fmt, struct tm *tm)
+__strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
 {
 	char	c;
 	const char *ptr;
-	int	i, len;
+	int	i, len, recurse = 0;
 	int Ealternative, Oalternative;
 	struct lc_time_T *tptr = __get_current_time_locale();
 
+	if (*flagsp & F_RECURSE)
+		recurse = 1;
+	*flagsp |= F_RECURSE;
+
+	if (*flagsp & F_ZERO)
+		(void) memset(tm, 0, sizeof (*tm));
+	*flagsp &= ~F_ZERO;
+
 	ptr = fmt;
 	while (*ptr != 0) {
 		if (*buf == 0)
@@ -60,12 +72,11 @@
 		c = *ptr++;
 
 		if (c != '%') {
-			if (isspace((unsigned char)c))
-				while (*buf != 0 &&
-				    isspace((unsigned char)*buf))
+			if (isspace(c))
+				while (isspace(*buf))
 					buf++;
 			else if (c != *buf++)
-				return (0);
+				return (NULL);
 			continue;
 		}
 
@@ -77,44 +88,42 @@
 		case 0:
 		case '%':
 			if (*buf++ != '%')
-				return (0);
+				return (NULL);
 			break;
 
 		case '+':
-			buf = __strptime(buf, tptr->date_fmt, tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'C':
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			/* XXX This will break for 3-digit centuries. */
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (i < 19)
-				return (0);
+				return (NULL);
 
 			tm->tm_year = i * 100 - 1900;
 			break;
 
 		case 'c':
-			buf = __strptime(buf, tptr->c_fmt, tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'D':
-			buf = __strptime(buf, "%m/%d/%y", tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'E':
@@ -130,71 +139,67 @@
 			goto label;
 
 		case 'F':
-			buf = __strptime(buf, "%Y-%m-%d", tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'R':
-			buf = __strptime(buf, "%H:%M", tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, "%H:%M", tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'r':
-			buf = __strptime(buf, tptr->ampm_fmt, tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'T':
-			buf = __strptime(buf, "%H:%M:%S", tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'X':
-			buf = __strptime(buf, tptr->X_fmt, tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'x':
-			buf = __strptime(buf, tptr->x_fmt, tm);
-			if (buf == 0)
-				return (0);
+			buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
+			if (buf == NULL)
+				return (NULL);
 			break;
 
 		case 'j':
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 3;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (i < 1 || i > 366)
-				return (0);
+				return (NULL);
 
 			tm->tm_yday = i - 1;
 			break;
 
 		case 'M':
 		case 'S':
-			if (*buf == 0 || isspace((unsigned char)*buf))
+			if (*buf == 0 || isspace(*buf))
 				break;
 
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -202,17 +207,16 @@
 
 			if (c == 'M') {
 				if (i > 59)
-					return (0);
+					return (NULL);
 				tm->tm_min = i;
 			} else {
 				if (i > 60)
-					return (0);
+					return (NULL);
 				tm->tm_sec = i;
 			}
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
@@ -228,28 +232,25 @@
 			 * XXX The %l specifier may gobble one too many
 			 * digits if used incorrectly.
 			 */
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (c == 'H' || c == 'k') {
 				if (i > 23)
-					return (0);
+					return (NULL);
 			} else if (i > 12)
-				return (0);
+				return (NULL);
 
 			tm->tm_hour = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
@@ -261,7 +262,7 @@
 			len = strlen(tptr->am);
 			if (strncasecmp(buf, tptr->am, len) == 0) {
 				if (tm->tm_hour > 12)
-					return (0);
+					return (NULL);
 				if (tm->tm_hour == 12)
 					tm->tm_hour = 0;
 				buf += len;
@@ -271,14 +272,14 @@
 			len = strlen(tptr->pm);
 			if (strncasecmp(buf, tptr->pm, len) == 0) {
 				if (tm->tm_hour > 12)
-					return (0);
+					return (NULL);
 				if (tm->tm_hour != 12)
 					tm->tm_hour += 12;
 				buf += len;
 				break;
 			}
 
-			return (0);
+			return (NULL);
 
 		case 'A':
 		case 'a':
@@ -292,7 +293,7 @@
 					break;
 			}
 			if (i == asizeof(tptr->weekday))
-				return (0);
+				return (NULL);
 
 			tm->tm_wday = i;
 			buf += len;
@@ -306,39 +307,35 @@
 			 * point to calculate a real value, so just check the
 			 * range for now.
 			 */
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (i > 53)
-				return (0);
+				return (NULL);
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
 		case 'w':
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			i = *buf - '0';
 			if (i > 6)
-				return (0);
+				return (NULL);
 
 			tm->tm_wday = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
@@ -352,25 +349,22 @@
 			 * XXX The %e specifier may gobble one too many
 			 * digits if used incorrectly.
 			 */
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (i > 31)
-				return (0);
+				return (NULL);
 
 			tm->tm_mday = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
@@ -395,47 +389,62 @@
 				}
 			}
 			if (i == asizeof(tptr->month))
-				return (0);
+				return (NULL);
 
 			tm->tm_mon = i;
 			buf += len;
 			break;
 
 		case 'm':
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
 			}
 			if (i < 1 || i > 12)
-				return (0);
+				return (NULL);
 
 			tm->tm_mon = i - 1;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != NULL && !isspace(*ptr))
 					ptr++;
 			break;
 
+		case 's':
+			{
+			char *cp;
+			int sverrno;
+			time_t t;
+
+			sverrno = errno;
+			errno = 0;
+			t = strtol(buf, &cp, 10);
+			if (errno == ERANGE) {
+				errno = sverrno;
+				return (NULL);
+			}
+			errno = sverrno;
+			buf = cp;
+			(void) gmtime_r(&t, tm);
+			*flagsp |= F_GMT;
+			}
+			break;
+
 		case 'Y':
 		case 'y':
-			if (*buf == 0 || isspace((unsigned char)*buf))
+			if (*buf == NULL || isspace(*buf))
 				break;
 
-			if (!isdigit((unsigned char)*buf))
-				return (0);
+			if (!isdigit(*buf))
+				return (NULL);
 
 			len = (c == 'Y') ? 4 : 2;
-			for (i = 0;
-			    len && isdigit((unsigned char)*buf);
-			    buf++) {
+			for (i = 0; len && isdigit(*buf); buf++) {
 				i *= 10;
 				i += *buf - '0';
 				len--;
@@ -445,13 +454,12 @@
 			if (c == 'y' && i < 69)
 				i += 100;
 			if (i < 0)
-				return (0);
+				return (NULL);
 
 			tm->tm_year = i;
 
-			if (*buf != 0 && isspace((unsigned char)*buf))
-				while (*ptr != 0 &&
-				    !isspace((unsigned char)*ptr))
+			if (isspace(*buf))
+				while (*ptr != 0 && !isspace(*ptr))
 					ptr++;
 			break;
 
@@ -460,48 +468,71 @@
 			const char *cp = buf;
 			char *zonestr;
 
-			while (isupper((unsigned char)*cp))
+			while (isupper(*cp))
 				++cp;
 			if (cp - buf) {
 				zonestr = alloca(cp - buf + 1);
 				(void) strncpy(zonestr, buf, cp - buf);
 				zonestr[cp - buf] = '\0';
 				tzset();
-				/*
-				 * Once upon a time this supported "GMT",
-				 * for GMT, but we removed this as Solaris
-				 * doesn't have it, and we lack the needed
-				 * timegm function.
-				 */
-				if (0 == strcmp(zonestr, tzname[0])) {
+				if (strcmp(zonestr, "GMT") == 0) {
+					*flagsp |= F_GMT;
+				} else if (0 == strcmp(zonestr, tzname[0])) {
 					tm->tm_isdst = 0;
 				} else if (0 == strcmp(zonestr, tzname[1])) {
 					tm->tm_isdst = 1;
 				} else {
-					return (0);
+					return (NULL);
 				}
 				buf += cp - buf;
 			}
 			}
 			break;
 
-		/*
-		 * Note that there used to be support %z and %s, but these
-		 * are not supported by Solaris, so we have removed them.
-		 * They would have required timegm() which is missing.
-		 */
+		case 'z':
+			{
+			int sign = 1;
+
+			if (*buf != '+') {
+				if (*buf == '-')
+					sign = -1;
+				else
+					return (NULL);
+			}
+			buf++;
+			i = 0;
+			for (len = 4; len > 0; len--) {
+				if (!isdigit(*buf))
+					return (NULL);
+				i *= 10;
+				i += *buf - '0';
+				buf++;
+			}
+
+			tm->tm_hour -= sign * (i / 100);
+			tm->tm_min -= sign * (i % 100);
+			*flagsp |= F_GMT;
+			}
+			break;
 		}
 	}
+
+	if (!recurse) {
+		if (buf && (*flagsp & F_GMT)) {
+			time_t t = timegm(tm);
+			(void) localtime_r(&t, tm);
+		}
+	}
+
 	return ((char *)buf);
 }
 
 char *
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
-	/* Legacy Solaris strptime clears the incoming tm structure. */
-	(void) memset(tm, 0, sizeof (*tm));
+	int	flags = F_ZERO;
 
-	return (__strptime(buf, fmt, tm));
+	return (__strptime(buf, fmt, tm, &flags));
 }
 
 /*
@@ -511,5 +542,7 @@
 char *
 __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
 {
-	return (__strptime(buf, fmt, tm));
+	int	flags = 0;
+
+	return (__strptime(buf, fmt, tm, &flags));
 }
--- a/usr/src/lib/libc/port/mapfile-vers	Fri Dec 03 07:32:02 2010 -0800
+++ b/usr/src/lib/libc/port/mapfile-vers	Sat Dec 04 17:33:07 2010 -0800
@@ -88,6 +88,11 @@
 $add amd64
 $endif
 
+SYMBOL_VERSION ILLUMOS_0.1 {	# Illumos additions
+    protected:
+        timegm;
+} SUNW_1.23;
+
 SYMBOL_VERSION SUNW_1.23 {	# SunOS 5.11 (Solaris 11)
     global:
 	_nl_domain_bindings;