1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if defined(LIBC_SCCS) && !defined(lint) 8: static char sccsid[] = "@(#)ctime.c 5.5 (Berkeley) 3/9/86"; 9: #endif LIBC_SCCS and not lint 10: 11: /* 12: * This routine converts time as follows. 13: * The epoch is 0000 Jan 1 1970 GMT. 14: * The argument time is in seconds since then. 15: * The localtime(t) entry returns a pointer to an array 16: * containing 17: * seconds (0-59) 18: * minutes (0-59) 19: * hours (0-23) 20: * day of month (1-31) 21: * month (0-11) 22: * year-1970 23: * weekday (0-6, Sun is 0) 24: * day of the year 25: * daylight savings flag 26: * 27: * The routine calls the system to determine the local 28: * timezone and whether Daylight Saving Time is permitted locally. 29: * (DST is then determined by the current local rules) 30: * 31: * The routine does not work 32: * in Saudi Arabia which runs on Solar time. 33: * 34: * asctime(tvec)) 35: * where tvec is produced by localtime 36: * returns a ptr to a character string 37: * that has the ascii time in the form 38: * Thu Jan 01 00:00:00 1970\n\0 39: * 0123456789012345678901234 5 40: * 0 1 2 41: * 42: * ctime(t) just calls localtime, then asctime. 43: */ 44: 45: #include <sys/time.h> 46: #include <sys/types.h> 47: #include <sys/timeb.h> 48: 49: static char cbuf[26]; 50: static int dmsize[12] = 51: { 52: 31, 53: 28, 54: 31, 55: 30, 56: 31, 57: 30, 58: 31, 59: 31, 60: 30, 61: 31, 62: 30, 63: 31 64: }; 65: 66: /* 67: * The following table is used for 1974 and 1975 and 68: * gives the day number of the first day after the Sunday of the 69: * change. 70: */ 71: struct dstab { 72: int dayyr; 73: int daylb; 74: int dayle; 75: }; 76: 77: static struct dstab usdaytab[] = { 78: 1974, 5, 333, /* 1974: Jan 6 - last Sun. in Nov */ 79: 1975, 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */ 80: 0, 119, 303, /* all other years: end Apr - end Oct */ 81: }; 82: static struct dstab ausdaytab[] = { 83: 1970, 400, 0, /* 1970: no daylight saving at all */ 84: 1971, 303, 0, /* 1971: daylight saving from Oct 31 */ 85: 1972, 303, 58, /* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */ 86: 0, 303, 65, /* others: -> Mar 7, Oct 31 -> */ 87: }; 88: 89: /* 90: * The European tables ... based on hearsay 91: * Believed correct for: 92: * WE: Great Britain, Portugal? 93: * ME: Belgium, Luxembourg, Netherlands, Denmark, Norway, 94: * Austria, Poland, Czechoslovakia, Sweden, Switzerland, 95: * DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia 96: * Finland (EE timezone, but ME dst rules) 97: * Eastern European dst is unknown, we'll make it ME until someone speaks up. 98: * EE: Bulgaria, Greece, Rumania, Turkey, Western Russia 99: * 100: * Ireland is unpredictable. (Years when Easter Sunday just happens ...) 101: * Years before 1983 are suspect. 102: */ 103: static struct dstab wedaytab[] = { 104: 1983, 89, 296, /* 1983: end March - end Oct */ 105: 0, 89, 303, /* others: end March - end Oct */ 106: }; 107: 108: static struct dstab medaytab[] = { 109: 1983, 89, 296, /* 1983: end March - end Oct */ 110: 0, 89, 272, /* others: end March - end Sep */ 111: }; 112: 113: /* 114: * Canada, same as the US, except no early 70's fluctuations. 115: * Can this really be right ?? 116: */ 117: static struct dstab candaytab[] = { 118: 0, 119, 303, /* all years: end Apr - end Oct */ 119: }; 120: 121: static struct dayrules { 122: int dst_type; /* number obtained from system */ 123: int dst_hrs; /* hours to add when dst on */ 124: struct dstab * dst_rules; /* one of the above */ 125: enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */ 126: } dayrules [] = { 127: DST_USA, 1, usdaytab, NTH, 128: DST_AUST, 1, ausdaytab, STH, 129: DST_WET, 1, wedaytab, NTH, 130: DST_MET, 1, medaytab, NTH, 131: DST_EET, 1, medaytab, NTH, /* XXX */ 132: DST_CAN, 1, candaytab, NTH, 133: -1, 134: }; 135: 136: struct tm *gmtime(); 137: char *ct_numb(); 138: struct tm *localtime(); 139: char *ctime(); 140: char *ct_num(); 141: char *asctime(); 142: 143: char * 144: ctime(t) 145: time_t *t; 146: { 147: return(asctime(localtime(t))); 148: } 149: 150: struct tm * 151: localtime(tim) 152: time_t *tim; 153: { 154: register int dayno; 155: register struct tm *ct; 156: register dalybeg, daylend; 157: register struct dayrules *dr; 158: register struct dstab *ds; 159: int year; 160: time_t copyt; 161: struct timeval curtime; 162: static struct timezone zone; 163: static int init = 0; 164: 165: if (!init) { 166: gettimeofday(&curtime, &zone); 167: init++; 168: } 169: copyt = *tim - (time_t)zone.tz_minuteswest*60; 170: ct = gmtime(©t); 171: dayno = ct->tm_yday; 172: for (dr = dayrules; dr->dst_type >= 0; dr++) 173: if (dr->dst_type == zone.tz_dsttime) 174: break; 175: if (dr->dst_type >= 0) { 176: year = ct->tm_year + 1900; 177: for (ds = dr->dst_rules; ds->dayyr; ds++) 178: if (ds->dayyr == year) 179: break; 180: dalybeg = ds->daylb; /* first Sun after dst starts */ 181: daylend = ds->dayle; /* first Sun after dst ends */ 182: dalybeg = sunday(ct, dalybeg); 183: daylend = sunday(ct, daylend); 184: switch (dr->dst_hemi) { 185: case NTH: 186: if (!( 187: (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 188: (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 189: )) 190: return(ct); 191: break; 192: case STH: 193: if (!( 194: (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 195: (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 196: )) 197: return(ct); 198: break; 199: default: 200: return(ct); 201: } 202: copyt += dr->dst_hrs*60*60; 203: ct = gmtime(©t); 204: ct->tm_isdst++; 205: } 206: return(ct); 207: } 208: 209: /* 210: * The argument is a 0-origin day number. 211: * The value is the day number of the last 212: * Sunday on or before the day. 213: */ 214: static 215: sunday(t, d) 216: register struct tm *t; 217: register int d; 218: { 219: if (d >= 58) 220: d += dysize(t->tm_year) - 365; 221: return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 222: } 223: 224: struct tm * 225: gmtime(tim) 226: time_t *tim; 227: { 228: register int d0, d1; 229: long hms, day; 230: register int *tp; 231: static struct tm xtime; 232: 233: /* 234: * break initial number into days 235: */ 236: hms = *tim % 86400; 237: day = *tim / 86400; 238: if (hms<0) { 239: hms += 86400; 240: day -= 1; 241: } 242: tp = (int *)&xtime; 243: 244: /* 245: * generate hours:minutes:seconds 246: */ 247: *tp++ = hms%60; 248: d1 = hms/60; 249: *tp++ = d1%60; 250: d1 /= 60; 251: *tp++ = d1; 252: 253: /* 254: * day is the day number. 255: * generate day of the week. 256: * The addend is 4 mod 7 (1/1/1970 was Thursday) 257: */ 258: 259: xtime.tm_wday = (day+7340036)%7; 260: 261: /* 262: * year number 263: */ 264: if (day>=0) for(d1=70; day >= dysize(d1); d1++) 265: day -= dysize(d1); 266: else for (d1=70; day<0; d1--) 267: day += dysize(d1-1); 268: xtime.tm_year = d1; 269: xtime.tm_yday = d0 = day; 270: 271: /* 272: * generate month 273: */ 274: 275: if (dysize(d1)==366) 276: dmsize[1] = 29; 277: for(d1=0; d0 >= dmsize[d1]; d1++) 278: d0 -= dmsize[d1]; 279: dmsize[1] = 28; 280: *tp++ = d0+1; 281: *tp++ = d1; 282: xtime.tm_isdst = 0; 283: return(&xtime); 284: } 285: 286: char * 287: asctime(t) 288: struct tm *t; 289: { 290: register char *cp, *ncp; 291: register int *tp; 292: 293: cp = cbuf; 294: for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 295: ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 296: cp = cbuf; 297: *cp++ = *ncp++; 298: *cp++ = *ncp++; 299: *cp++ = *ncp++; 300: cp++; 301: tp = &t->tm_mon; 302: ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 303: *cp++ = *ncp++; 304: *cp++ = *ncp++; 305: *cp++ = *ncp++; 306: cp = ct_numb(cp, *--tp); 307: cp = ct_numb(cp, *--tp+100); 308: cp = ct_numb(cp, *--tp+100); 309: cp = ct_numb(cp, *--tp+100); 310: if (t->tm_year>=100) { 311: cp[1] = '2'; 312: cp[2] = '0' + (t->tm_year-100) / 100; 313: } 314: cp += 2; 315: cp = ct_numb(cp, t->tm_year+100); 316: return(cbuf); 317: } 318: 319: dysize(y) 320: { 321: if((y%4) == 0) 322: return(366); 323: return(365); 324: } 325: 326: static char * 327: ct_numb(cp, n) 328: register char *cp; 329: { 330: cp++; 331: if (n>=10) 332: *cp++ = (n/10)%10 + '0'; 333: else 334: *cp++ = ' '; 335: *cp++ = n%10 + '0'; 336: return(cp); 337: }