1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* 7*0Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 8*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 9*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 10*0Sstevel@tonic-gate */ 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gate /* 15*0Sstevel@tonic-gate * This localtime is a modified version of offtime from libc, which does not 16*0Sstevel@tonic-gate * bother to figure out the time zone from the kernel, from environment 17*0Sstevel@tonic-gate * variables, or from Unix files. 18*0Sstevel@tonic-gate */ 19*0Sstevel@tonic-gate 20*0Sstevel@tonic-gate #include <sys/types.h> 21*0Sstevel@tonic-gate #include <sys/salib.h> 22*0Sstevel@tonic-gate #include <tzfile.h> 23*0Sstevel@tonic-gate #include <errno.h> 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate static int mon_lengths[2][MONS_PER_YEAR] = { 26*0Sstevel@tonic-gate 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 27*0Sstevel@tonic-gate 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 28*0Sstevel@tonic-gate }; 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate static int year_lengths[2] = { 31*0Sstevel@tonic-gate DAYS_PER_NYEAR, DAYS_PER_LYEAR 32*0Sstevel@tonic-gate }; 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate struct tm * 35*0Sstevel@tonic-gate localtime(const time_t *clock) 36*0Sstevel@tonic-gate { 37*0Sstevel@tonic-gate struct tm *tmp; 38*0Sstevel@tonic-gate long days; 39*0Sstevel@tonic-gate long rem; 40*0Sstevel@tonic-gate int y; 41*0Sstevel@tonic-gate int yleap; 42*0Sstevel@tonic-gate int *ip; 43*0Sstevel@tonic-gate static struct tm tm; 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate tmp = &tm; 46*0Sstevel@tonic-gate days = *clock / SECS_PER_DAY; 47*0Sstevel@tonic-gate rem = *clock % SECS_PER_DAY; 48*0Sstevel@tonic-gate while (rem < 0) { 49*0Sstevel@tonic-gate rem += SECS_PER_DAY; 50*0Sstevel@tonic-gate --days; 51*0Sstevel@tonic-gate } 52*0Sstevel@tonic-gate while (rem >= SECS_PER_DAY) { 53*0Sstevel@tonic-gate rem -= SECS_PER_DAY; 54*0Sstevel@tonic-gate ++days; 55*0Sstevel@tonic-gate } 56*0Sstevel@tonic-gate tmp->tm_hour = (int)(rem / SECS_PER_HOUR); 57*0Sstevel@tonic-gate rem = rem % SECS_PER_HOUR; 58*0Sstevel@tonic-gate tmp->tm_min = (int)(rem / SECS_PER_MIN); 59*0Sstevel@tonic-gate tmp->tm_sec = (int)(rem % SECS_PER_MIN); 60*0Sstevel@tonic-gate tmp->tm_wday = (int)((EPOCH_WDAY + days) % DAYS_PER_WEEK); 61*0Sstevel@tonic-gate if (tmp->tm_wday < 0) 62*0Sstevel@tonic-gate tmp->tm_wday += DAYS_PER_WEEK; 63*0Sstevel@tonic-gate y = EPOCH_YEAR; 64*0Sstevel@tonic-gate if (days >= 0) { 65*0Sstevel@tonic-gate for (;;) { 66*0Sstevel@tonic-gate yleap = isleap(y); 67*0Sstevel@tonic-gate if (days < (long)year_lengths[yleap]) 68*0Sstevel@tonic-gate break; 69*0Sstevel@tonic-gate if (++y > 9999) { 70*0Sstevel@tonic-gate errno = EOVERFLOW; 71*0Sstevel@tonic-gate return (NULL); 72*0Sstevel@tonic-gate } 73*0Sstevel@tonic-gate days = days - (long)year_lengths[yleap]; 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate } else { 76*0Sstevel@tonic-gate do { 77*0Sstevel@tonic-gate if (--y < 0) { 78*0Sstevel@tonic-gate errno = EOVERFLOW; 79*0Sstevel@tonic-gate return (NULL); 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate yleap = isleap(y); 82*0Sstevel@tonic-gate days = days + (long)year_lengths[yleap]; 83*0Sstevel@tonic-gate } while (days < 0); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate tmp->tm_year = y - TM_YEAR_BASE; 86*0Sstevel@tonic-gate tmp->tm_yday = (int)days; 87*0Sstevel@tonic-gate ip = mon_lengths[yleap]; 88*0Sstevel@tonic-gate for (tmp->tm_mon = 0; days >= (long)ip[tmp->tm_mon]; ++(tmp->tm_mon)) 89*0Sstevel@tonic-gate days = days - (long)ip[tmp->tm_mon]; 90*0Sstevel@tonic-gate tmp->tm_mday = (int)(days + 1); 91*0Sstevel@tonic-gate tmp->tm_isdst = 0; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate return (tmp); 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate /* 97*0Sstevel@tonic-gate * So is ctime... 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * This routine converts time as follows. 102*0Sstevel@tonic-gate * The epoch is 0000 Jan 1 1970 GMT. 103*0Sstevel@tonic-gate * The argument time is in seconds since then. 104*0Sstevel@tonic-gate * The localtime(t) entry returns a pointer to an array 105*0Sstevel@tonic-gate * containing 106*0Sstevel@tonic-gate * seconds (0-59) 107*0Sstevel@tonic-gate * minutes (0-59) 108*0Sstevel@tonic-gate * hours (0-23) 109*0Sstevel@tonic-gate * day of month (1-31) 110*0Sstevel@tonic-gate * month (0-11) 111*0Sstevel@tonic-gate * year-1970 112*0Sstevel@tonic-gate * weekday (0-6, Sun is 0) 113*0Sstevel@tonic-gate * day of the year 114*0Sstevel@tonic-gate * daylight savings flag 115*0Sstevel@tonic-gate * 116*0Sstevel@tonic-gate * The routine corrects for daylight saving 117*0Sstevel@tonic-gate * time and will work in any time zone provided 118*0Sstevel@tonic-gate * "timezone" is adjusted to the difference between 119*0Sstevel@tonic-gate * Greenwich and local standard time (measured in seconds). 120*0Sstevel@tonic-gate * In places like Michigan "daylight" must 121*0Sstevel@tonic-gate * be initialized to 0 to prevent the conversion 122*0Sstevel@tonic-gate * to daylight time. 123*0Sstevel@tonic-gate * There is a table which accounts for the peculiarities 124*0Sstevel@tonic-gate * undergone by daylight time in 1974-1975. 125*0Sstevel@tonic-gate * 126*0Sstevel@tonic-gate * The routine does not work 127*0Sstevel@tonic-gate * in Saudi Arabia which runs on Solar time. 128*0Sstevel@tonic-gate * 129*0Sstevel@tonic-gate * asctime(tvec) 130*0Sstevel@tonic-gate * where tvec is produced by localtime 131*0Sstevel@tonic-gate * returns a ptr to a character string 132*0Sstevel@tonic-gate * that has the ascii time in the form 133*0Sstevel@tonic-gate * Thu Jan 01 00:00:00 1970\n\0 134*0Sstevel@tonic-gate * 01234567890123456789012345 135*0Sstevel@tonic-gate * 0 1 2 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * ctime(t) just calls localtime, then asctime. 138*0Sstevel@tonic-gate * 139*0Sstevel@tonic-gate * tzset() looks for an environment variable named 140*0Sstevel@tonic-gate * TZ. 141*0Sstevel@tonic-gate * If the variable is present, it will set the external 142*0Sstevel@tonic-gate * variables "timezone", "altzone", "daylight", and "tzname" 143*0Sstevel@tonic-gate * appropriately. It is called by localtime, and 144*0Sstevel@tonic-gate * may also be called explicitly by the user. 145*0Sstevel@tonic-gate */ 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate #define dysize(A) (((A)%4)? 365: 366) 150*0Sstevel@tonic-gate #define CBUFSIZ 26 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate /* 153*0Sstevel@tonic-gate * POSIX.1c standard version of the function asctime_r. 154*0Sstevel@tonic-gate * User gets it via static asctime_r from the header file. 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate char * 157*0Sstevel@tonic-gate __posix_asctime_r(const struct tm *t, char *cbuf) 158*0Sstevel@tonic-gate { 159*0Sstevel@tonic-gate const char *Date = "Day Mon 00 00:00:00 1900\n"; 160*0Sstevel@tonic-gate const char *Day = "SunMonTueWedThuFriSat"; 161*0Sstevel@tonic-gate const char *Month = "JanFebMarAprMayJunJulAugSepOctNovDec"; 162*0Sstevel@tonic-gate static char *ct_numb(); 163*0Sstevel@tonic-gate const char *ncp; 164*0Sstevel@tonic-gate const int *tp; 165*0Sstevel@tonic-gate char *cp; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if (t == NULL) 168*0Sstevel@tonic-gate return (NULL); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate cp = cbuf; 171*0Sstevel@tonic-gate for (ncp = Date; *cp++ = *ncp++; /* */); 172*0Sstevel@tonic-gate ncp = Day + (3*t->tm_wday); 173*0Sstevel@tonic-gate cp = cbuf; 174*0Sstevel@tonic-gate *cp++ = *ncp++; 175*0Sstevel@tonic-gate *cp++ = *ncp++; 176*0Sstevel@tonic-gate *cp++ = *ncp++; 177*0Sstevel@tonic-gate cp++; 178*0Sstevel@tonic-gate tp = &t->tm_mon; 179*0Sstevel@tonic-gate ncp = Month + ((*tp) * 3); 180*0Sstevel@tonic-gate *cp++ = *ncp++; 181*0Sstevel@tonic-gate *cp++ = *ncp++; 182*0Sstevel@tonic-gate *cp++ = *ncp++; 183*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp); 184*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100); 185*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100); 186*0Sstevel@tonic-gate cp = ct_numb(cp, *--tp+100); 187*0Sstevel@tonic-gate if (t->tm_year > 9999) { 188*0Sstevel@tonic-gate errno = EOVERFLOW; 189*0Sstevel@tonic-gate return (NULL); 190*0Sstevel@tonic-gate } else { 191*0Sstevel@tonic-gate uint_t hun = 19 + (t->tm_year / 100); 192*0Sstevel@tonic-gate cp[1] = (hun / 10) + '0'; 193*0Sstevel@tonic-gate cp[2] = (hun % 10) + '0'; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate cp += 2; 196*0Sstevel@tonic-gate cp = ct_numb(cp, t->tm_year+100); 197*0Sstevel@tonic-gate return (cbuf); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * POSIX.1c Draft-6 version of the function asctime_r. 202*0Sstevel@tonic-gate * It was implemented by Solaris 2.3. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate char * 205*0Sstevel@tonic-gate _asctime_r(const struct tm *t, char *cbuf, int buflen) 206*0Sstevel@tonic-gate { 207*0Sstevel@tonic-gate if (buflen < CBUFSIZ) { 208*0Sstevel@tonic-gate errno = ERANGE; 209*0Sstevel@tonic-gate return (NULL); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate return (__posix_asctime_r(t, cbuf)); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate char * 215*0Sstevel@tonic-gate ctime(const time_t *t) 216*0Sstevel@tonic-gate { 217*0Sstevel@tonic-gate return (asctime(localtime(t))); 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate char * 222*0Sstevel@tonic-gate asctime(const struct tm *t) 223*0Sstevel@tonic-gate { 224*0Sstevel@tonic-gate static char cbuf[CBUFSIZ]; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate return (_asctime_r(t, cbuf, CBUFSIZ)); 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate static char * 231*0Sstevel@tonic-gate ct_numb(char *cp, int n) 232*0Sstevel@tonic-gate { 233*0Sstevel@tonic-gate cp++; 234*0Sstevel@tonic-gate if (n >= 10) 235*0Sstevel@tonic-gate *cp++ = (n/10)%10 + '0'; 236*0Sstevel@tonic-gate else 237*0Sstevel@tonic-gate *cp++ = ' '; /* Pad with blanks */ 238*0Sstevel@tonic-gate *cp++ = n%10 + '0'; 239*0Sstevel@tonic-gate return (cp); 240*0Sstevel@tonic-gate } 241