10Sstevel@tonic-gate /*
2*9694SScott.Rotondo@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
80Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
90Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate */
110Sstevel@tonic-gate
120Sstevel@tonic-gate /*
130Sstevel@tonic-gate * This localtime is a modified version of offtime from libc, which does not
140Sstevel@tonic-gate * bother to figure out the time zone from the kernel, from environment
150Sstevel@tonic-gate * variables, or from Unix files.
160Sstevel@tonic-gate */
170Sstevel@tonic-gate
180Sstevel@tonic-gate #include <sys/types.h>
190Sstevel@tonic-gate #include <sys/salib.h>
200Sstevel@tonic-gate #include <tzfile.h>
210Sstevel@tonic-gate #include <errno.h>
220Sstevel@tonic-gate
230Sstevel@tonic-gate static int mon_lengths[2][MONS_PER_YEAR] = {
240Sstevel@tonic-gate 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
250Sstevel@tonic-gate 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
260Sstevel@tonic-gate };
270Sstevel@tonic-gate
280Sstevel@tonic-gate static int year_lengths[2] = {
290Sstevel@tonic-gate DAYS_PER_NYEAR, DAYS_PER_LYEAR
300Sstevel@tonic-gate };
310Sstevel@tonic-gate
320Sstevel@tonic-gate struct tm *
localtime(const time_t * clock)330Sstevel@tonic-gate localtime(const time_t *clock)
340Sstevel@tonic-gate {
350Sstevel@tonic-gate struct tm *tmp;
360Sstevel@tonic-gate long days;
370Sstevel@tonic-gate long rem;
380Sstevel@tonic-gate int y;
390Sstevel@tonic-gate int yleap;
400Sstevel@tonic-gate int *ip;
410Sstevel@tonic-gate static struct tm tm;
420Sstevel@tonic-gate
430Sstevel@tonic-gate tmp = &tm;
440Sstevel@tonic-gate days = *clock / SECS_PER_DAY;
450Sstevel@tonic-gate rem = *clock % SECS_PER_DAY;
460Sstevel@tonic-gate while (rem < 0) {
470Sstevel@tonic-gate rem += SECS_PER_DAY;
480Sstevel@tonic-gate --days;
490Sstevel@tonic-gate }
500Sstevel@tonic-gate while (rem >= SECS_PER_DAY) {
510Sstevel@tonic-gate rem -= SECS_PER_DAY;
520Sstevel@tonic-gate ++days;
530Sstevel@tonic-gate }
540Sstevel@tonic-gate tmp->tm_hour = (int)(rem / SECS_PER_HOUR);
550Sstevel@tonic-gate rem = rem % SECS_PER_HOUR;
560Sstevel@tonic-gate tmp->tm_min = (int)(rem / SECS_PER_MIN);
570Sstevel@tonic-gate tmp->tm_sec = (int)(rem % SECS_PER_MIN);
580Sstevel@tonic-gate tmp->tm_wday = (int)((EPOCH_WDAY + days) % DAYS_PER_WEEK);
590Sstevel@tonic-gate if (tmp->tm_wday < 0)
600Sstevel@tonic-gate tmp->tm_wday += DAYS_PER_WEEK;
610Sstevel@tonic-gate y = EPOCH_YEAR;
620Sstevel@tonic-gate if (days >= 0) {
630Sstevel@tonic-gate for (;;) {
640Sstevel@tonic-gate yleap = isleap(y);
650Sstevel@tonic-gate if (days < (long)year_lengths[yleap])
660Sstevel@tonic-gate break;
670Sstevel@tonic-gate if (++y > 9999) {
680Sstevel@tonic-gate errno = EOVERFLOW;
690Sstevel@tonic-gate return (NULL);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate days = days - (long)year_lengths[yleap];
720Sstevel@tonic-gate }
730Sstevel@tonic-gate } else {
740Sstevel@tonic-gate do {
750Sstevel@tonic-gate if (--y < 0) {
760Sstevel@tonic-gate errno = EOVERFLOW;
770Sstevel@tonic-gate return (NULL);
780Sstevel@tonic-gate }
790Sstevel@tonic-gate yleap = isleap(y);
800Sstevel@tonic-gate days = days + (long)year_lengths[yleap];
810Sstevel@tonic-gate } while (days < 0);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate tmp->tm_year = y - TM_YEAR_BASE;
840Sstevel@tonic-gate tmp->tm_yday = (int)days;
850Sstevel@tonic-gate ip = mon_lengths[yleap];
860Sstevel@tonic-gate for (tmp->tm_mon = 0; days >= (long)ip[tmp->tm_mon]; ++(tmp->tm_mon))
870Sstevel@tonic-gate days = days - (long)ip[tmp->tm_mon];
880Sstevel@tonic-gate tmp->tm_mday = (int)(days + 1);
890Sstevel@tonic-gate tmp->tm_isdst = 0;
900Sstevel@tonic-gate
910Sstevel@tonic-gate return (tmp);
920Sstevel@tonic-gate }
930Sstevel@tonic-gate
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * So is ctime...
960Sstevel@tonic-gate */
970Sstevel@tonic-gate
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate * This routine converts time as follows.
1000Sstevel@tonic-gate * The epoch is 0000 Jan 1 1970 GMT.
1010Sstevel@tonic-gate * The argument time is in seconds since then.
1020Sstevel@tonic-gate * The localtime(t) entry returns a pointer to an array
1030Sstevel@tonic-gate * containing
1040Sstevel@tonic-gate * seconds (0-59)
1050Sstevel@tonic-gate * minutes (0-59)
1060Sstevel@tonic-gate * hours (0-23)
1070Sstevel@tonic-gate * day of month (1-31)
1080Sstevel@tonic-gate * month (0-11)
1090Sstevel@tonic-gate * year-1970
1100Sstevel@tonic-gate * weekday (0-6, Sun is 0)
1110Sstevel@tonic-gate * day of the year
1120Sstevel@tonic-gate * daylight savings flag
1130Sstevel@tonic-gate *
1140Sstevel@tonic-gate * The routine corrects for daylight saving
1150Sstevel@tonic-gate * time and will work in any time zone provided
1160Sstevel@tonic-gate * "timezone" is adjusted to the difference between
1170Sstevel@tonic-gate * Greenwich and local standard time (measured in seconds).
1180Sstevel@tonic-gate * In places like Michigan "daylight" must
1190Sstevel@tonic-gate * be initialized to 0 to prevent the conversion
1200Sstevel@tonic-gate * to daylight time.
1210Sstevel@tonic-gate * There is a table which accounts for the peculiarities
1220Sstevel@tonic-gate * undergone by daylight time in 1974-1975.
1230Sstevel@tonic-gate *
1240Sstevel@tonic-gate * The routine does not work
1250Sstevel@tonic-gate * in Saudi Arabia which runs on Solar time.
1260Sstevel@tonic-gate *
1270Sstevel@tonic-gate * asctime(tvec)
1280Sstevel@tonic-gate * where tvec is produced by localtime
1290Sstevel@tonic-gate * returns a ptr to a character string
1300Sstevel@tonic-gate * that has the ascii time in the form
1310Sstevel@tonic-gate * Thu Jan 01 00:00:00 1970\n\0
1320Sstevel@tonic-gate * 01234567890123456789012345
1330Sstevel@tonic-gate * 0 1 2
1340Sstevel@tonic-gate *
1350Sstevel@tonic-gate * ctime(t) just calls localtime, then asctime.
1360Sstevel@tonic-gate *
1370Sstevel@tonic-gate * tzset() looks for an environment variable named
1380Sstevel@tonic-gate * TZ.
1390Sstevel@tonic-gate * If the variable is present, it will set the external
1400Sstevel@tonic-gate * variables "timezone", "altzone", "daylight", and "tzname"
1410Sstevel@tonic-gate * appropriately. It is called by localtime, and
1420Sstevel@tonic-gate * may also be called explicitly by the user.
1430Sstevel@tonic-gate */
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate #define dysize(A) (((A)%4)? 365: 366)
1480Sstevel@tonic-gate #define CBUFSIZ 26
1490Sstevel@tonic-gate
150*9694SScott.Rotondo@Sun.COM static char *ct_numb();
151*9694SScott.Rotondo@Sun.COM
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * POSIX.1c standard version of the function asctime_r.
1540Sstevel@tonic-gate * User gets it via static asctime_r from the header file.
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate char *
__posix_asctime_r(const struct tm * t,char * cbuf)1570Sstevel@tonic-gate __posix_asctime_r(const struct tm *t, char *cbuf)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate const char *Date = "Day Mon 00 00:00:00 1900\n";
1600Sstevel@tonic-gate const char *Day = "SunMonTueWedThuFriSat";
1610Sstevel@tonic-gate const char *Month = "JanFebMarAprMayJunJulAugSepOctNovDec";
1620Sstevel@tonic-gate const char *ncp;
1630Sstevel@tonic-gate const int *tp;
1640Sstevel@tonic-gate char *cp;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate if (t == NULL)
1670Sstevel@tonic-gate return (NULL);
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate cp = cbuf;
1706812Sraf for (ncp = Date; *cp++ = *ncp++; /* */)
1716812Sraf ;
1720Sstevel@tonic-gate ncp = Day + (3*t->tm_wday);
1730Sstevel@tonic-gate cp = cbuf;
1740Sstevel@tonic-gate *cp++ = *ncp++;
1750Sstevel@tonic-gate *cp++ = *ncp++;
1760Sstevel@tonic-gate *cp++ = *ncp++;
1770Sstevel@tonic-gate cp++;
1780Sstevel@tonic-gate tp = &t->tm_mon;
1790Sstevel@tonic-gate ncp = Month + ((*tp) * 3);
1800Sstevel@tonic-gate *cp++ = *ncp++;
1810Sstevel@tonic-gate *cp++ = *ncp++;
1820Sstevel@tonic-gate *cp++ = *ncp++;
1830Sstevel@tonic-gate cp = ct_numb(cp, *--tp);
1840Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100);
1850Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100);
1860Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100);
1870Sstevel@tonic-gate if (t->tm_year > 9999) {
1880Sstevel@tonic-gate errno = EOVERFLOW;
1890Sstevel@tonic-gate return (NULL);
1900Sstevel@tonic-gate } else {
1910Sstevel@tonic-gate uint_t hun = 19 + (t->tm_year / 100);
1920Sstevel@tonic-gate cp[1] = (hun / 10) + '0';
1930Sstevel@tonic-gate cp[2] = (hun % 10) + '0';
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate cp += 2;
1960Sstevel@tonic-gate cp = ct_numb(cp, t->tm_year+100);
1970Sstevel@tonic-gate return (cbuf);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate /*
2010Sstevel@tonic-gate * POSIX.1c Draft-6 version of the function asctime_r.
2020Sstevel@tonic-gate * It was implemented by Solaris 2.3.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate char *
asctime_r(const struct tm * t,char * cbuf,int buflen)2056812Sraf asctime_r(const struct tm *t, char *cbuf, int buflen)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate if (buflen < CBUFSIZ) {
2080Sstevel@tonic-gate errno = ERANGE;
2090Sstevel@tonic-gate return (NULL);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate return (__posix_asctime_r(t, cbuf));
2120Sstevel@tonic-gate }
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate char *
ctime(const time_t * t)2150Sstevel@tonic-gate ctime(const time_t *t)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate return (asctime(localtime(t)));
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate char *
asctime(const struct tm * t)2220Sstevel@tonic-gate asctime(const struct tm *t)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate static char cbuf[CBUFSIZ];
2250Sstevel@tonic-gate
2266812Sraf return (asctime_r(t, cbuf, CBUFSIZ));
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate static char *
ct_numb(char * cp,int n)2310Sstevel@tonic-gate ct_numb(char *cp, int n)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate cp++;
2340Sstevel@tonic-gate if (n >= 10)
2350Sstevel@tonic-gate *cp++ = (n/10)%10 + '0';
2360Sstevel@tonic-gate else
2370Sstevel@tonic-gate *cp++ = ' '; /* Pad with blanks */
2380Sstevel@tonic-gate *cp++ = n%10 + '0';
2390Sstevel@tonic-gate return (cp);
2400Sstevel@tonic-gate }
241