17c478bd9Sstevel@tonic-gate /*
2*7257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
87c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley software License Agreement
97c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
107c478bd9Sstevel@tonic-gate  */
117c478bd9Sstevel@tonic-gate 
127c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
137c478bd9Sstevel@tonic-gate 
147c478bd9Sstevel@tonic-gate /*
157c478bd9Sstevel@tonic-gate  * This localtime is a modified version of offtime from libc, which does not
167c478bd9Sstevel@tonic-gate  * bother to figure out the time zone from the kernel, from environment
177c478bd9Sstevel@tonic-gate  * variables, or from Unix files.
187c478bd9Sstevel@tonic-gate  */
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate #include <sys/types.h>
217c478bd9Sstevel@tonic-gate #include <sys/salib.h>
227c478bd9Sstevel@tonic-gate #include <tzfile.h>
237c478bd9Sstevel@tonic-gate #include <errno.h>
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate static int mon_lengths[2][MONS_PER_YEAR] = {
267c478bd9Sstevel@tonic-gate 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
277c478bd9Sstevel@tonic-gate 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
287c478bd9Sstevel@tonic-gate };
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate static int year_lengths[2] = {
317c478bd9Sstevel@tonic-gate 	DAYS_PER_NYEAR, DAYS_PER_LYEAR
327c478bd9Sstevel@tonic-gate };
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate struct tm *
357c478bd9Sstevel@tonic-gate localtime(const time_t *clock)
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate 	struct tm *tmp;
387c478bd9Sstevel@tonic-gate 	long days;
397c478bd9Sstevel@tonic-gate 	long rem;
407c478bd9Sstevel@tonic-gate 	int y;
417c478bd9Sstevel@tonic-gate 	int yleap;
427c478bd9Sstevel@tonic-gate 	int *ip;
437c478bd9Sstevel@tonic-gate 	static struct tm tm;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate 	tmp = &tm;
467c478bd9Sstevel@tonic-gate 	days = *clock / SECS_PER_DAY;
477c478bd9Sstevel@tonic-gate 	rem = *clock % SECS_PER_DAY;
487c478bd9Sstevel@tonic-gate 	while (rem < 0) {
497c478bd9Sstevel@tonic-gate 		rem += SECS_PER_DAY;
507c478bd9Sstevel@tonic-gate 		--days;
517c478bd9Sstevel@tonic-gate 	}
527c478bd9Sstevel@tonic-gate 	while (rem >= SECS_PER_DAY) {
537c478bd9Sstevel@tonic-gate 		rem -= SECS_PER_DAY;
547c478bd9Sstevel@tonic-gate 		++days;
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 	tmp->tm_hour = (int)(rem / SECS_PER_HOUR);
577c478bd9Sstevel@tonic-gate 	rem = rem % SECS_PER_HOUR;
587c478bd9Sstevel@tonic-gate 	tmp->tm_min = (int)(rem / SECS_PER_MIN);
597c478bd9Sstevel@tonic-gate 	tmp->tm_sec = (int)(rem % SECS_PER_MIN);
607c478bd9Sstevel@tonic-gate 	tmp->tm_wday = (int)((EPOCH_WDAY + days) % DAYS_PER_WEEK);
617c478bd9Sstevel@tonic-gate 	if (tmp->tm_wday < 0)
627c478bd9Sstevel@tonic-gate 		tmp->tm_wday += DAYS_PER_WEEK;
637c478bd9Sstevel@tonic-gate 	y = EPOCH_YEAR;
647c478bd9Sstevel@tonic-gate 	if (days >= 0) {
657c478bd9Sstevel@tonic-gate 		for (;;) {
667c478bd9Sstevel@tonic-gate 			yleap = isleap(y);
677c478bd9Sstevel@tonic-gate 			if (days < (long)year_lengths[yleap])
687c478bd9Sstevel@tonic-gate 				break;
697c478bd9Sstevel@tonic-gate 			if (++y > 9999) {
707c478bd9Sstevel@tonic-gate 				errno = EOVERFLOW;
717c478bd9Sstevel@tonic-gate 				return (NULL);
727c478bd9Sstevel@tonic-gate 			}
737c478bd9Sstevel@tonic-gate 			days = days - (long)year_lengths[yleap];
747c478bd9Sstevel@tonic-gate 		}
757c478bd9Sstevel@tonic-gate 	} else {
767c478bd9Sstevel@tonic-gate 		do {
777c478bd9Sstevel@tonic-gate 			if (--y < 0) {
787c478bd9Sstevel@tonic-gate 				errno = EOVERFLOW;
797c478bd9Sstevel@tonic-gate 				return (NULL);
807c478bd9Sstevel@tonic-gate 			}
817c478bd9Sstevel@tonic-gate 			yleap = isleap(y);
827c478bd9Sstevel@tonic-gate 			days = days + (long)year_lengths[yleap];
837c478bd9Sstevel@tonic-gate 		} while (days < 0);
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate 	tmp->tm_year = y - TM_YEAR_BASE;
867c478bd9Sstevel@tonic-gate 	tmp->tm_yday = (int)days;
877c478bd9Sstevel@tonic-gate 	ip = mon_lengths[yleap];
887c478bd9Sstevel@tonic-gate 	for (tmp->tm_mon = 0; days >= (long)ip[tmp->tm_mon]; ++(tmp->tm_mon))
897c478bd9Sstevel@tonic-gate 		days = days - (long)ip[tmp->tm_mon];
907c478bd9Sstevel@tonic-gate 	tmp->tm_mday = (int)(days + 1);
917c478bd9Sstevel@tonic-gate 	tmp->tm_isdst = 0;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	return (tmp);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * So is ctime...
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * This routine converts time as follows.
1027c478bd9Sstevel@tonic-gate  * The epoch is 0000 Jan 1 1970 GMT.
1037c478bd9Sstevel@tonic-gate  * The argument time is in seconds since then.
1047c478bd9Sstevel@tonic-gate  * The localtime(t) entry returns a pointer to an array
1057c478bd9Sstevel@tonic-gate  * containing
1067c478bd9Sstevel@tonic-gate  *  seconds (0-59)
1077c478bd9Sstevel@tonic-gate  *  minutes (0-59)
1087c478bd9Sstevel@tonic-gate  *  hours (0-23)
1097c478bd9Sstevel@tonic-gate  *  day of month (1-31)
1107c478bd9Sstevel@tonic-gate  *  month (0-11)
1117c478bd9Sstevel@tonic-gate  *  year-1970
1127c478bd9Sstevel@tonic-gate  *  weekday (0-6, Sun is 0)
1137c478bd9Sstevel@tonic-gate  *  day of the year
1147c478bd9Sstevel@tonic-gate  *  daylight savings flag
1157c478bd9Sstevel@tonic-gate  *
1167c478bd9Sstevel@tonic-gate  * The routine corrects for daylight saving
1177c478bd9Sstevel@tonic-gate  * time and will work in any time zone provided
1187c478bd9Sstevel@tonic-gate  * "timezone" is adjusted to the difference between
1197c478bd9Sstevel@tonic-gate  * Greenwich and local standard time (measured in seconds).
1207c478bd9Sstevel@tonic-gate  * In places like Michigan "daylight" must
1217c478bd9Sstevel@tonic-gate  * be initialized to 0 to prevent the conversion
1227c478bd9Sstevel@tonic-gate  * to daylight time.
1237c478bd9Sstevel@tonic-gate  * There is a table which accounts for the peculiarities
1247c478bd9Sstevel@tonic-gate  * undergone by daylight time in 1974-1975.
1257c478bd9Sstevel@tonic-gate  *
1267c478bd9Sstevel@tonic-gate  * The routine does not work
1277c478bd9Sstevel@tonic-gate  * in Saudi Arabia which runs on Solar time.
1287c478bd9Sstevel@tonic-gate  *
1297c478bd9Sstevel@tonic-gate  * asctime(tvec)
1307c478bd9Sstevel@tonic-gate  * where tvec is produced by localtime
1317c478bd9Sstevel@tonic-gate  * returns a ptr to a character string
1327c478bd9Sstevel@tonic-gate  * that has the ascii time in the form
1337c478bd9Sstevel@tonic-gate  *	Thu Jan 01 00:00:00 1970\n\0
1347c478bd9Sstevel@tonic-gate  *	01234567890123456789012345
1357c478bd9Sstevel@tonic-gate  *	0	  1	    2
1367c478bd9Sstevel@tonic-gate  *
1377c478bd9Sstevel@tonic-gate  * ctime(t) just calls localtime, then asctime.
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  * tzset() looks for an environment variable named
1407c478bd9Sstevel@tonic-gate  * TZ.
1417c478bd9Sstevel@tonic-gate  * If the variable is present, it will set the external
1427c478bd9Sstevel@tonic-gate  * variables "timezone", "altzone", "daylight", and "tzname"
1437c478bd9Sstevel@tonic-gate  * appropriately. It is called by localtime, and
1447c478bd9Sstevel@tonic-gate  * may also be called explicitly by the user.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate #define	dysize(A) (((A)%4)? 365: 366)
1507c478bd9Sstevel@tonic-gate #define	CBUFSIZ 26
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function asctime_r.
1547c478bd9Sstevel@tonic-gate  * User gets it via static asctime_r from the header file.
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate char *
1577c478bd9Sstevel@tonic-gate __posix_asctime_r(const struct tm *t, char *cbuf)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	const char *Date = "Day Mon 00 00:00:00 1900\n";
1607c478bd9Sstevel@tonic-gate 	const char *Day  = "SunMonTueWedThuFriSat";
1617c478bd9Sstevel@tonic-gate 	const char *Month = "JanFebMarAprMayJunJulAugSepOctNovDec";
1627c478bd9Sstevel@tonic-gate 	static char *ct_numb();
1637c478bd9Sstevel@tonic-gate 	const char *ncp;
1647c478bd9Sstevel@tonic-gate 	const int *tp;
1657c478bd9Sstevel@tonic-gate 	char *cp;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if (t == NULL)
1687c478bd9Sstevel@tonic-gate 		return (NULL);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	cp = cbuf;
171*7257d1b4Sraf 	for (ncp = Date; *cp++ = *ncp++; /* */)
172*7257d1b4Sraf 		;
1737c478bd9Sstevel@tonic-gate 	ncp = Day + (3*t->tm_wday);
1747c478bd9Sstevel@tonic-gate 	cp = cbuf;
1757c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1767c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1777c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1787c478bd9Sstevel@tonic-gate 	cp++;
1797c478bd9Sstevel@tonic-gate 	tp = &t->tm_mon;
1807c478bd9Sstevel@tonic-gate 	ncp = Month + ((*tp) * 3);
1817c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1827c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1837c478bd9Sstevel@tonic-gate 	*cp++ = *ncp++;
1847c478bd9Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp);
1857c478bd9Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
1867c478bd9Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
1877c478bd9Sstevel@tonic-gate 	cp = ct_numb(cp, *--tp+100);
1887c478bd9Sstevel@tonic-gate 	if (t->tm_year > 9999) {
1897c478bd9Sstevel@tonic-gate 		errno = EOVERFLOW;
1907c478bd9Sstevel@tonic-gate 		return (NULL);
1917c478bd9Sstevel@tonic-gate 	} else {
1927c478bd9Sstevel@tonic-gate 		uint_t hun = 19 + (t->tm_year / 100);
1937c478bd9Sstevel@tonic-gate 		cp[1] = (hun / 10) + '0';
1947c478bd9Sstevel@tonic-gate 		cp[2] = (hun % 10) + '0';
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	cp += 2;
1977c478bd9Sstevel@tonic-gate 	cp = ct_numb(cp, t->tm_year+100);
1987c478bd9Sstevel@tonic-gate 	return (cbuf);
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function asctime_r.
2037c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate char *
206*7257d1b4Sraf asctime_r(const struct tm *t, char *cbuf, int buflen)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	if (buflen < CBUFSIZ) {
2097c478bd9Sstevel@tonic-gate 		errno = ERANGE;
2107c478bd9Sstevel@tonic-gate 		return (NULL);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 	return (__posix_asctime_r(t, cbuf));
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate char *
2167c478bd9Sstevel@tonic-gate ctime(const time_t *t)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	return (asctime(localtime(t)));
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate char *
2237c478bd9Sstevel@tonic-gate asctime(const struct tm *t)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	static char cbuf[CBUFSIZ];
2267c478bd9Sstevel@tonic-gate 
227*7257d1b4Sraf 	return (asctime_r(t, cbuf, CBUFSIZ));
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate static char *
2327c478bd9Sstevel@tonic-gate ct_numb(char *cp, int n)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	cp++;
2357c478bd9Sstevel@tonic-gate 	if (n >= 10)
2367c478bd9Sstevel@tonic-gate 		*cp++ = (n/10)%10 + '0';
2377c478bd9Sstevel@tonic-gate 	else
2387c478bd9Sstevel@tonic-gate 		*cp++ = ' ';		/* Pad with blanks */
2397c478bd9Sstevel@tonic-gate 	*cp++ = n%10 + '0';
2407c478bd9Sstevel@tonic-gate 	return (cp);
2417c478bd9Sstevel@tonic-gate }
242