+ _pthread_mutex_lock(&gmtime_mutex);
+- if (gmtime_key < 0) {
+- if (_pthread_key_create(&gmtime_key, free) < 0) {
++ if (gmtime_key == (pthread_key_t)-1) {
++ gmtime_key = __LIBC_PTHREAD_KEY_GMTIME;
++ if (pthread_key_init_np(gmtime_key, free) < 0) {
+ _pthread_mutex_unlock(&gmtime_mutex);
+ return(NULL);
+ }
+@@ -1253,12 +1665,20 @@ const time_t * const timep;
+ }
+ _pthread_setspecific(gmtime_key, p_tm);
+ }
++#ifdef __LP64__
++ return gmtsub(timep, 0L, p_tm);
++#else /* !__LP64__ */
+ gmtsub(timep, 0L, p_tm);
+ return(p_tm);
++#endif /* __LP64__ */
+ }
+ else {
++#ifdef __LP64__
++ return gmtsub(timep, 0L, &tm);
++#else /* !__LP64__ */
+ gmtsub(timep, 0L, &tm);
+ return(&tm);
++#endif /* __LP64__ */
+ }
+ }
+
+@@ -1271,8 +1691,13 @@ gmtime_r(timep, tm)
+ const time_t * const timep;
+ struct tm * tm;
+ {
++
++#ifdef __LP64__
++ return gmtsub(timep, 0L, tm);
++#else /* !__LP64__ */
+ gmtsub(timep, 0L, tm);
+ return tm;
++#endif /* __LP64__ */
+ }
+
+ #ifdef STD_INSPIRED
+@@ -1282,13 +1707,21 @@ offtime(timep, offset)
+ const time_t * const timep;
+ const long offset;
+ {
++#ifdef __LP64__
++ return gmtsub(timep, offset, &tm);
++#else /* !__LP64__ */
+ gmtsub(timep, offset, &tm);
+ return &tm;
++#endif /* __LP64__ */
+ }
+
+ #endif /* defined STD_INSPIRED */
+
++#ifdef __LP64__
++static struct tm *
++#else /* !__LP64__ */
+ static void
++#endif /* __LP64__ */
+ timesub(timep, offset, sp, tmp)
+ const time_t * const timep;
+ const long offset;
+@@ -1365,7 +1798,12 @@ struct tm * const tmp;
+ if (tmp->tm_wday < 0)
+ tmp->tm_wday += DAYSPERWEEK;
+ y = EPOCH_YEAR;
+-#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
++#define _LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
++#ifdef __LP64__
++#define LEAPS_THRU_END_OF(y) ((y) >= 0 ? _LEAPS_THRU_END_OF(y) : _LEAPS_THRU_END_OF((y) + 1) - 1)
++#else /* !__LP64__ */
++#define LEAPS_THRU_END_OF(y) _LEAPS_THRU_END_OF(y)
++#endif /* __LP64__ */
+ while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+ long newy;
+
+@@ -1377,7 +1815,16 @@ struct tm * const tmp;
+ LEAPS_THRU_END_OF(y - 1);
+ y = newy;
+ }
++#ifdef __LP64__
++ y -= TM_YEAR_BASE;
++ if (y < INT_MIN || y > INT_MAX) {
++ errno = EOVERFLOW;
++ return NULL;
++ }
++ tmp->tm_year = y;
++#else /* !__LP64__ */
+ tmp->tm_year = y - TM_YEAR_BASE;
++#endif /* __LP64__ */
+ tmp->tm_yday = (int) days;
+ ip = mon_lengths[yleap];
+ for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
+@@ -1387,6 +1834,9 @@ struct tm * const tmp;
+ #ifdef TM_GMTOFF
+ tmp->TM_GMTOFF = offset;
+ #endif /* defined TM_GMTOFF */
++#ifdef __LP64__
++ return tmp;
++#endif /* __LP64__ */
+ }
+
+ char *
+@@ -1399,7 +1849,20 @@ const time_t * const timep;
+ ** to local time in the form of a string. It is equivalent to
+ ** asctime(localtime(timer))
+ */
++#ifdef __LP64__
++ /*
++ * In 64-bit, the timep value may produce a time value with a year
++ * that exceeds 32-bits in size (won't fit in struct tm), so localtime
++ * will return NULL.
++ */
++ struct tm *tm = localtime(timep);
++
++ if (tm == NULL)
++ return NULL;
++ return asctime(tm);
++#else /* !__LP64__ */
+ return asctime(localtime(timep));
++#endif /* __LP64__ */
+ }
+
+ char *
+@@ -1409,7 +1872,18 @@ char * buf;
+ {
+ struct tm tm;
+
++#ifdef __LP64__
++ /*
++ * In 64-bit, the timep value may produce a time value with a year
++ * that exceeds 32-bits in size (won't fit in struct tm), so localtime_r
++ * will return NULL.
++ */
++ if (localtime_r(timep, &tm) == NULL)
++ return NULL;
++ return asctime_r(&tm, buf);
++#else /* !__LP64__ */
+ return asctime_r(localtime_r(timep, &tm), buf);
++#endif /* __LP64__ */
+ }
+
+ /*
+@@ -1464,8 +1938,14 @@ const struct tm * const btmp;
+ {
+ int result;
+
+- if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+- (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
++ /*
++ * Assume that atmp and btmp point to normalized tm strutures.
++ * So only arithmetic with tm_year could overflow in 64-bit.
++ */
++ if (atmp->tm_year != btmp->tm_year) {
++ return (atmp->tm_year > btmp->tm_year ? 1 : -1);
++ }
++ if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+@@ -1474,12 +1954,17 @@ const struct tm * const btmp;
+ }
+
+ static time_t
+-time2sub(tmp, funcp, offset, okayp, do_norm_secs)
++time2sub(tmp, funcp, offset, okayp, do_norm_secs, unix03)
+ struct tm * const tmp;
++#ifdef __LP64__
++struct tm *(* const funcp)(const time_t*, long, struct tm*);
++#else /* !__LP64__ */
+ void (* const funcp)(const time_t*, long, struct tm*);
++#endif /* __LP64__ */
+ const long offset;
+ int * const okayp;
+ const int do_norm_secs;
++int unix03;
+ {
+ const struct state * sp;
+ int dir;
+@@ -1489,6 +1974,9 @@ const int do_norm_secs;
+ time_t newt;
+ time_t t;
+ struct tm yourtm, mytm;
++#ifdef __LP64__
++ long year, il;
++#endif /* __LP64__ */
+
+ *okayp = FALSE;
+ yourtm = *tmp;
+@@ -1507,33 +1995,64 @@ const int do_norm_secs;
+ ** Turn yourtm.tm_year into an actual year number for now.
+ ** It is converted back to an offset from TM_YEAR_BASE later.
+ */
++#ifdef __LP64__
++ year = (long)yourtm.tm_year + TM_YEAR_BASE;
++#else /* !__LP64__ */
+ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
+ return WRONG;
++#endif /* __LP64__ */
+ while (yourtm.tm_mday <= 0) {
++#ifdef __LP64__
++ year--;
++ il = year + (1 < yourtm.tm_mon);
++ yourtm.tm_mday += year_lengths[isleap(il)];
++#else /* !__LP64__ */
+ if (increment_overflow(&yourtm.tm_year, -1))
+ return WRONG;
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);
+ yourtm.tm_mday += year_lengths[isleap(i)];
++#endif /* __LP64__ */
+ }
+ while (yourtm.tm_mday > DAYSPERLYEAR) {
++#ifdef __LP64__
++ il = year + (1 < yourtm.tm_mon);
++ yourtm.tm_mday -= year_lengths[isleap(il)];
++ year++;
++#else /* !__LP64__ */
+ i = yourtm.tm_year + (1 < yourtm.tm_mon);
+ yourtm.tm_mday -= year_lengths[isleap(i)];
+ if (increment_overflow(&yourtm.tm_year, 1))
+ return WRONG;
++#endif /* __LP64__ */
+ }
+ for ( ; ; ) {
++#ifdef __LP64__
++ i = mon_lengths[isleap(year)][yourtm.tm_mon];
++#else /* !__LP64__ */
+ i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
++#endif /* __LP64__ */
+ if (yourtm.tm_mday <= i)
+ break;
+ yourtm.tm_mday -= i;
+ if (++yourtm.tm_mon >= MONSPERYEAR) {
+ yourtm.tm_mon = 0;
++#ifdef __LP64__
++ year++;
++#else /* !__LP64__ */
+ if (increment_overflow(&yourtm.tm_year, 1))
+ return WRONG;
++#endif /* __LP64__ */
+ }
+ }
++#ifdef __LP64__
++ year -= TM_YEAR_BASE;
++ if (year > INT_MAX || year < INT_MIN)
++ return WRONG;
++ yourtm.tm_year = year;
++#else /* !__LP64__ */
+ if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
+ return WRONG;
++#endif /* __LP64__ */
+ /* Don't go below 1900 for POLA */
+ if (yourtm.tm_year < 0)
+ return WRONG;
+@@ -1560,13 +2079,21 @@ const int do_norm_secs;
+ ** Divide the search space in half
+ ** (this works whether time_t is signed or unsigned).
+ */
++#ifdef __LP64__
++ /* optimization: see if the value is 31-bit (signed) */
++ t = (((time_t) 1) << (TYPE_BIT(int) - 1)) - 1;
++ bits = ((*funcp)(&t, offset, &mytm) == NULL || tmcomp(&mytm, &yourtm) < 0) ? TYPE_BIT(time_t) - 1 : TYPE_BIT(int) - 1;
++#else /* !__LP64__ */
+ bits = TYPE_BIT(time_t) - 1;
++#endif /* __LP64__ */
+ /*
+- ** If we have more than this, we will overflow tm_year for tmcomp().
+- ** We should really return an error if we cannot represent it.
++ ** In 64-bit, we now return an error if we cannot represent the
++ ** struct tm value in a time_t. And tmcomp() is fixed to avoid
++ ** overflow in tm_year. So we only put a cap on bits because time_t
++ ** can't be larger that 56 bit (when tm_year == INT_MAX).
+ */
+- if (bits > 48)
+- bits = 48;
++ if (bits > 56)
++ bits = 56;
+ /*
+ ** If time_t is signed, then 0 is just above the median,
+ ** assuming two's complement arithmetic.
+@@ -1574,8 +2101,19 @@ const int do_norm_secs;
+ */
+ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
+ for ( ; ; ) {
++#ifdef __LP64__
++ if ((*funcp)(&t, offset, &mytm) == NULL) {
++ /* we overflowed, so t is too big */
++ dir = 1;
++ goto skip_tmcomp;
++ }
++#else /* !__LP64__ */
+ (*funcp)(&t, offset, &mytm);
++#endif /* __LP64__ */
+ dir = tmcomp(&mytm, &yourtm);
++#ifdef __LP64__
++skip_tmcomp:
++#endif /* __LP64__ */
+ if (dir != 0) {
+ if (bits-- < 0)
+ return WRONG;
+@@ -1586,6 +2124,9 @@ const int do_norm_secs;
+ else t += ((time_t) 1) << bits;
+ continue;
+ }
++ sp = (funcp == localsub) ? lclptr : gmtptr;
++ if (unix03 && sp->typecnt == 1 && yourtm.tm_isdst > 0)
++ yourtm.tm_isdst = 0; /* alternative time does not apply */
+ if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
+ break;
+ /*
+@@ -1594,7 +2135,6 @@ const int do_norm_secs;
+ ** It's okay to guess wrong since the guess
+ ** gets checked.
+ */
+- sp = (funcp == localsub) ? lclptr : gmtptr;
+ #ifdef ALL_STATE
+ if (sp == NULL)
+ return WRONG;
+@@ -1607,7 +2147,12 @@ const int do_norm_secs;
+ continue;
+ newt = t + sp->ttis[j].tt_gmtoff -
+ sp->ttis[i].tt_gmtoff;
++#ifdef __LP64__
++ if ((*funcp)(&newt, offset, &mytm) == NULL)
++ return WRONG;
++#else /* !__LP64__ */
+ (*funcp)(&newt, offset, &mytm);
++#endif /* __LP64__ */
+ if (tmcomp(&mytm, &yourtm) != 0)
+ continue;
+ if (mytm.tm_isdst != yourtm.tm_isdst)
+@@ -1626,17 +2171,27 @@ label:
+ if ((newt < t) != (saved_seconds < 0))
+ return WRONG;
+ t = newt;
++#ifdef __LP64__
++ if ((*funcp)(&t, offset, tmp) == NULL)
++ return WRONG;
++#else /* !__LP64__ */
+ (*funcp)(&t, offset, tmp);
++#endif /* __LP64__ */
+ *okayp = TRUE;
+ return t;
+ }
+
+ static time_t
+-time2(tmp, funcp, offset, okayp)
++time2(tmp, funcp, offset, okayp, unix03)
+ struct tm * const tmp;
++#ifdef __LP64__
++struct tm *(* const funcp)(const time_t*, long, struct tm*);
++#else /* !__LP64__ */
+ void (* const funcp)(const time_t*, long, struct tm*);
++#endif /* __LP64__ */
+ const long offset;
+ int * const okayp;
++int unix03;
+ {
+ time_t t;
+
+@@ -1645,15 +2200,20 @@ int * const okayp;
+ ** (in case tm_sec contains a value associated with a leap second).
+ ** If that fails, try with normalization of seconds.
+ */
+- t = time2sub(tmp, funcp, offset, okayp, FALSE);
+- return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
++ t = time2sub(tmp, funcp, offset, okayp, FALSE, unix03);
++ return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, unix03);
+ }
+
+-static time_t
+-time1(tmp, funcp, offset)
++__private_extern__ time_t
++time1(tmp, funcp, offset, unix03)
+ struct tm * const tmp;
++#ifdef __LP64__
++struct tm *(* const funcp)(const time_t *, long, struct tm *);
++#else /* !__LP64__ */
+ void (* const funcp)(const time_t *, long, struct tm *);
++#endif /* __LP64__ */
+ const long offset;
++int unix03;
+ {
+ time_t t;
+ const struct state * sp;
+@@ -1667,7 +2227,7 @@ const long offset;
+
+ if (tmp->tm_isdst > 1)
+ tmp->tm_isdst = 1;
+- t = time2(tmp, funcp, offset, &okay);
++ t = time2(tmp, funcp, offset, &okay, unix03);
+ #ifdef PCTS
+ /*
+ ** PCTS code courtesy Grant Sullivan (grant@osf.org).
+@@ -1711,7 +2271,7 @@ const long offset;
+ tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
+ sp->ttis[samei].tt_gmtoff;
+ tmp->tm_isdst = !tmp->tm_isdst;
+- t = time2(tmp, funcp, offset, &okay);
++ t = time2(tmp, funcp, offset, &okay, unix03);
+ if (okay)
+ return t;
+ tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
+@@ -1721,19 +2281,25 @@ const long offset;
+ }
+ return WRONG;
+ }
++#else /* BUILDING_VARIANT */
++__private_extern__ pthread_rwlock_t lcl_rwlock;
++#endif /* BUILDING_VARIANT */
+
+ time_t
+ mktime(tmp)
+ struct tm * const tmp;
+ {
+ time_t mktime_return_value;
++ int serrno = errno;
+ _RWLOCK_RDLOCK(&lcl_rwlock);
+ tzset_basic(1);
+- mktime_return_value = time1(tmp, localsub, 0L);
++ mktime_return_value = time1(tmp, localsub, 0L, __DARWIN_UNIX03);
+ _RWLOCK_UNLOCK(&lcl_rwlock);
++ errno = serrno;
+ return(mktime_return_value);
+ }
+
++#if !BUILDING_VARIANT
+ #ifdef STD_INSPIRED
+
+ time_t
+@@ -1749,7 +2315,7 @@ timegm(tmp)
+ struct tm * const tmp;
+ {
+ tmp->tm_isdst = 0;
+- return time1(tmp, gmtsub, 0L);
++ return time1(tmp, gmtsub, 0L, __DARWIN_UNIX03);
+ }
+
+ time_t
+@@ -1758,7 +2324,7 @@ struct tm * const tmp;
+ const long offset;
+ {
+ tmp->tm_isdst = 0;
+- return time1(tmp, gmtsub, offset);
++ return time1(tmp, gmtsub, offset, __DARWIN_UNIX03);
+ }
+
+ #endif /* defined STD_INSPIRED */
+@@ -1858,3 +2424,4 @@ time_t t;
+ }
+
+ #endif /* defined STD_INSPIRED */
++#endif /* !BUILDING_VARIANT */