1 /* @(#)ctime.c 4.2 (Berkeley) 06/10/83 */ 2 /* 3 * This routine converts time as follows. 4 * The epoch is 0000 Jan 1 1970 GMT. 5 * The argument time is in seconds since then. 6 * The localtime(t) entry returns a pointer to an array 7 * containing 8 * seconds (0-59) 9 * minutes (0-59) 10 * hours (0-23) 11 * day of month (1-31) 12 * month (0-11) 13 * year-1970 14 * weekday (0-6, Sun is 0) 15 * day of the year 16 * daylight savings flag 17 * 18 * The routine calls the system to determine the local 19 * timezone and whether Daylight Saving Time is permitted locally. 20 * (DST is then determined by the current US standard rules) 21 * There is a table that accounts for the peculiarities 22 * undergone by daylight time in 1974-1975. 23 * 24 * The routine does not work 25 * in Saudi Arabia which runs on Solar time. 26 * 27 * asctime(tvec)) 28 * where tvec is produced by localtime 29 * returns a ptr to a character string 30 * that has the ascii time in the form 31 * Thu Jan 01 00:00:00 1970n0\\ 32 * 01234567890123456789012345 33 * 0 1 2 34 * 35 * ctime(t) just calls localtime, then asctime. 36 */ 37 38 #include <time.h> 39 #include <sys/types.h> 40 #include <sys/timeb.h> 41 42 static char cbuf[26]; 43 static int dmsize[12] = 44 { 45 31, 46 28, 47 31, 48 30, 49 31, 50 30, 51 31, 52 31, 53 30, 54 31, 55 30, 56 31 57 }; 58 59 /* 60 * The following table is used for 1974 and 1975 and 61 * gives the day number of the first day after the Sunday of the 62 * change. 63 */ 64 struct dstab { 65 int dayyr; 66 int daylb; 67 int dayle; 68 }; 69 70 static struct dstab usdaytab[] = { 71 1974, 5, 333, /* 1974: Jan 6 - last Sun. in Nov */ 72 1975, 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */ 73 0, 119, 303, /* all other years: end Apr - end Oct */ 74 }; 75 static struct dstab ausdaytab[] = { 76 1970, 400, 0, /* 1970: no daylight saving at all */ 77 1971, 303, 0, /* 1971: daylight saving from Oct 31 */ 78 1972, 303, 58, /* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */ 79 0, 303, 65, /* others: -> Mar 7, Oct 31 -> */ 80 }; 81 82 static struct dayrules { 83 int dst_type; /* number obtained from system */ 84 int dst_hrs; /* hours to add when dst on */ 85 struct dstab * dst_rules; /* one of the above */ 86 enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */ 87 } dayrules [] = { 88 DST_USA, 1, usdaytab, NTH, 89 DST_AUST, 1, ausdaytab, STH, 90 -1, 91 }; 92 93 struct tm *gmtime(); 94 char *ct_numb(); 95 struct tm *localtime(); 96 char *ctime(); 97 char *ct_num(); 98 char *asctime(); 99 100 char * 101 ctime(t) 102 unsigned long *t; 103 { 104 return(asctime(localtime(t))); 105 } 106 107 struct tm * 108 localtime(tim) 109 unsigned long *tim; 110 { 111 register int dayno; 112 register struct tm *ct; 113 register dalybeg, daylend; 114 register struct dayrules *dr; 115 register struct dstab *ds; 116 int year; 117 unsigned long copyt; 118 struct timeval curtime; 119 struct timezone zone; 120 121 gettimeofday(&curtime, &zone); 122 copyt = *tim - (unsigned long)zone.tz_minuteswest*60; 123 ct = gmtime(©t); 124 dayno = ct->tm_yday; 125 for (dr = dayrules; dr->dst_type >= 0; dr++) 126 if (dr->dst_type == zone.tz_dsttime) 127 break; 128 if (dr->dst_type >= 0) { 129 year = ct->tm_year + 1900; 130 for (ds = dr->dst_rules; ds->dayyr; ds++) 131 if (ds->dayyr == year) 132 break; 133 dalybeg = ds->daylb; /* first Sun after dst starts */ 134 daylend = ds->dayle; /* first Sun after dst ends */ 135 dalybeg = sunday(ct, dalybeg); 136 daylend = sunday(ct, daylend); 137 switch (dr->dst_hemi) { 138 case NTH: 139 if (!( 140 (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 141 (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 142 )) 143 return(ct); 144 break; 145 case STH: 146 if (!( 147 (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 148 (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 149 )) 150 return(ct); 151 break; 152 default: 153 return(ct); 154 } 155 copyt += dr->dst_hrs*60*60; 156 ct = gmtime(©t); 157 ct->tm_isdst++; 158 } 159 return(ct); 160 } 161 162 /* 163 * The argument is a 0-origin day number. 164 * The value is the day number of the first 165 * Sunday on or after the day. 166 */ 167 static 168 sunday(t, d) 169 register struct tm *t; 170 register int d; 171 { 172 if (d >= 58) 173 d += dysize(t->tm_year) - 365; 174 return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 175 } 176 177 struct tm * 178 gmtime(tim) 179 unsigned long *tim; 180 { 181 register int d0, d1; 182 unsigned long hms, day; 183 register int *tp; 184 static struct tm xtime; 185 186 /* 187 * break initial number into days 188 */ 189 hms = *tim % 86400; 190 day = *tim / 86400; 191 if (hms<0) { 192 hms += 86400; 193 day -= 1; 194 } 195 tp = (int *)&xtime; 196 197 /* 198 * generate hours:minutes:seconds 199 */ 200 *tp++ = hms%60; 201 d1 = hms/60; 202 *tp++ = d1%60; 203 d1 /= 60; 204 *tp++ = d1; 205 206 /* 207 * day is the day number. 208 * generate day of the week. 209 * The addend is 4 mod 7 (1/1/1970 was Thursday) 210 */ 211 212 xtime.tm_wday = (day+7340036)%7; 213 214 /* 215 * year number 216 */ 217 if (day>=0) for(d1=70; day >= dysize(d1); d1++) 218 day -= dysize(d1); 219 else for (d1=70; day<0; d1--) 220 day += dysize(d1-1); 221 xtime.tm_year = d1; 222 xtime.tm_yday = d0 = day; 223 224 /* 225 * generate month 226 */ 227 228 if (dysize(d1)==366) 229 dmsize[1] = 29; 230 for(d1=0; d0 >= dmsize[d1]; d1++) 231 d0 -= dmsize[d1]; 232 dmsize[1] = 28; 233 *tp++ = d0+1; 234 *tp++ = d1; 235 xtime.tm_isdst = 0; 236 return(&xtime); 237 } 238 239 char * 240 asctime(t) 241 struct tm *t; 242 { 243 register char *cp, *ncp; 244 register int *tp; 245 246 cp = cbuf; 247 for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 248 ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 249 cp = cbuf; 250 *cp++ = *ncp++; 251 *cp++ = *ncp++; 252 *cp++ = *ncp++; 253 cp++; 254 tp = &t->tm_mon; 255 ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 256 *cp++ = *ncp++; 257 *cp++ = *ncp++; 258 *cp++ = *ncp++; 259 cp = ct_numb(cp, *--tp); 260 cp = ct_numb(cp, *--tp+100); 261 cp = ct_numb(cp, *--tp+100); 262 cp = ct_numb(cp, *--tp+100); 263 if (t->tm_year>=100) { 264 cp[1] = '2'; 265 cp[2] = '0' + t->tm_year >= 200; 266 } 267 cp += 2; 268 cp = ct_numb(cp, t->tm_year+100); 269 return(cbuf); 270 } 271 272 dysize(y) 273 { 274 if((y%4) == 0) 275 return(366); 276 return(365); 277 } 278 279 static char * 280 ct_numb(cp, n) 281 register char *cp; 282 { 283 cp++; 284 if (n>=10) 285 *cp++ = (n/10)%10 + '0'; 286 else 287 *cp++ = ' '; 288 *cp++ = n%10 + '0'; 289 return(cp); 290 } 291