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