113582Ssam #ifndef lint 2*13876Ssam static char sccsid[] = "@(#)ctime.c 4.4 (Berkeley) 07/09/83"; 313582Ssam #endif 41959Swnj /* 51959Swnj * This routine converts time as follows. 61959Swnj * The epoch is 0000 Jan 1 1970 GMT. 71959Swnj * The argument time is in seconds since then. 81959Swnj * The localtime(t) entry returns a pointer to an array 91959Swnj * containing 101959Swnj * seconds (0-59) 111959Swnj * minutes (0-59) 121959Swnj * hours (0-23) 131959Swnj * day of month (1-31) 141959Swnj * month (0-11) 151959Swnj * year-1970 161959Swnj * weekday (0-6, Sun is 0) 171959Swnj * day of the year 181959Swnj * daylight savings flag 191959Swnj * 201959Swnj * The routine calls the system to determine the local 211959Swnj * timezone and whether Daylight Saving Time is permitted locally. 22*13876Ssam * (DST is then determined by the current local rules) 231959Swnj * 241959Swnj * The routine does not work 251959Swnj * in Saudi Arabia which runs on Solar time. 261959Swnj * 271959Swnj * asctime(tvec)) 281959Swnj * where tvec is produced by localtime 291959Swnj * returns a ptr to a character string 301959Swnj * that has the ascii time in the form 311959Swnj * Thu Jan 01 00:00:00 1970n0\\ 321959Swnj * 01234567890123456789012345 331959Swnj * 0 1 2 341959Swnj * 351959Swnj * ctime(t) just calls localtime, then asctime. 361959Swnj */ 371959Swnj 3813582Ssam #include <sys/time.h> 391959Swnj #include <sys/types.h> 401959Swnj #include <sys/timeb.h> 411959Swnj 421959Swnj static char cbuf[26]; 431959Swnj static int dmsize[12] = 441959Swnj { 451959Swnj 31, 461959Swnj 28, 471959Swnj 31, 481959Swnj 30, 491959Swnj 31, 501959Swnj 30, 511959Swnj 31, 521959Swnj 31, 531959Swnj 30, 541959Swnj 31, 551959Swnj 30, 561959Swnj 31 571959Swnj }; 581959Swnj 591959Swnj /* 601959Swnj * The following table is used for 1974 and 1975 and 611959Swnj * gives the day number of the first day after the Sunday of the 621959Swnj * change. 631959Swnj */ 6412974Ssam struct dstab { 6512974Ssam int dayyr; 661959Swnj int daylb; 671959Swnj int dayle; 681959Swnj }; 691959Swnj 7012974Ssam static struct dstab usdaytab[] = { 7112974Ssam 1974, 5, 333, /* 1974: Jan 6 - last Sun. in Nov */ 7212974Ssam 1975, 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */ 7312974Ssam 0, 119, 303, /* all other years: end Apr - end Oct */ 7412974Ssam }; 7512974Ssam static struct dstab ausdaytab[] = { 7612974Ssam 1970, 400, 0, /* 1970: no daylight saving at all */ 7712974Ssam 1971, 303, 0, /* 1971: daylight saving from Oct 31 */ 7812974Ssam 1972, 303, 58, /* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */ 7912974Ssam 0, 303, 65, /* others: -> Mar 7, Oct 31 -> */ 8012974Ssam }; 8112974Ssam 82*13876Ssam /* 83*13876Ssam * The European tables ... based on hearsay 84*13876Ssam * Believed correct for: 85*13876Ssam * WE: Great Britain, Ireland, Portugal 86*13876Ssam * ME: Belgium, Luxembourg, Netherlands, Denmark, Norway, 87*13876Ssam * Austria, Poland, Czechoslovakia, Sweden, Switzerland, 88*13876Ssam * DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia 89*13876Ssam * Eastern European dst is unknown, we'll make it ME until someone speaks up. 90*13876Ssam * EE: Bulgaria, Finland, Greece, Rumania, Turkey, Western Russia 91*13876Ssam */ 92*13876Ssam static struct dstab wedaytab[] = { 93*13876Ssam 1983, 86, 303, /* 1983: end March - end Oct */ 94*13876Ssam 1984, 86, 303, /* 1984: end March - end Oct */ 95*13876Ssam 1985, 86, 303, /* 1985: end March - end Oct */ 96*13876Ssam 0, 400, 0, /* others: no daylight saving at all ??? */ 97*13876Ssam }; 98*13876Ssam 99*13876Ssam static struct dstab medaytab[] = { 100*13876Ssam 1983, 86, 272, /* 1983: end March - end Sep */ 101*13876Ssam 1984, 86, 272, /* 1984: end March - end Sep */ 102*13876Ssam 1985, 86, 272, /* 1985: end March - end Sep */ 103*13876Ssam 0, 400, 0, /* others: no daylight saving at all ??? */ 104*13876Ssam }; 105*13876Ssam 10612974Ssam static struct dayrules { 10712974Ssam int dst_type; /* number obtained from system */ 10812974Ssam int dst_hrs; /* hours to add when dst on */ 10912974Ssam struct dstab * dst_rules; /* one of the above */ 11012974Ssam enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */ 11112974Ssam } dayrules [] = { 11212974Ssam DST_USA, 1, usdaytab, NTH, 11312974Ssam DST_AUST, 1, ausdaytab, STH, 114*13876Ssam DST_WET, 1, wedaytab, NTH, 115*13876Ssam DST_MET, 1, medaytab, NTH, 116*13876Ssam DST_EET, 1, medaytab, NTH, /* XXX */ 11712974Ssam -1, 11812974Ssam }; 11912974Ssam 1201959Swnj struct tm *gmtime(); 1211959Swnj char *ct_numb(); 1221959Swnj struct tm *localtime(); 1231959Swnj char *ctime(); 1241959Swnj char *ct_num(); 1251959Swnj char *asctime(); 1261959Swnj 1271959Swnj char * 1281959Swnj ctime(t) 12912974Ssam unsigned long *t; 1301959Swnj { 1311959Swnj return(asctime(localtime(t))); 1321959Swnj } 1331959Swnj 1341959Swnj struct tm * 1351959Swnj localtime(tim) 13612974Ssam unsigned long *tim; 1371959Swnj { 1381959Swnj register int dayno; 1391959Swnj register struct tm *ct; 14012974Ssam register dalybeg, daylend; 14112974Ssam register struct dayrules *dr; 14212974Ssam register struct dstab *ds; 14312974Ssam int year; 14412974Ssam unsigned long copyt; 14512974Ssam struct timeval curtime; 14612974Ssam struct timezone zone; 1471959Swnj 14812974Ssam gettimeofday(&curtime, &zone); 14912974Ssam copyt = *tim - (unsigned long)zone.tz_minuteswest*60; 1501959Swnj ct = gmtime(©t); 1511959Swnj dayno = ct->tm_yday; 15212974Ssam for (dr = dayrules; dr->dst_type >= 0; dr++) 15312974Ssam if (dr->dst_type == zone.tz_dsttime) 15412974Ssam break; 15512974Ssam if (dr->dst_type >= 0) { 15612974Ssam year = ct->tm_year + 1900; 15712974Ssam for (ds = dr->dst_rules; ds->dayyr; ds++) 15812974Ssam if (ds->dayyr == year) 15912974Ssam break; 16012974Ssam dalybeg = ds->daylb; /* first Sun after dst starts */ 16112974Ssam daylend = ds->dayle; /* first Sun after dst ends */ 16212974Ssam dalybeg = sunday(ct, dalybeg); 16312974Ssam daylend = sunday(ct, daylend); 16412974Ssam switch (dr->dst_hemi) { 16512974Ssam case NTH: 16612974Ssam if (!( 16712974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 16812974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 16912974Ssam )) 17012974Ssam return(ct); 17112974Ssam break; 17212974Ssam case STH: 17312974Ssam if (!( 17412974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 17512974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 17612974Ssam )) 17712974Ssam return(ct); 17812974Ssam break; 17912974Ssam default: 18012974Ssam return(ct); 18112974Ssam } 18212974Ssam copyt += dr->dst_hrs*60*60; 1831959Swnj ct = gmtime(©t); 1841959Swnj ct->tm_isdst++; 1851959Swnj } 1861959Swnj return(ct); 1871959Swnj } 1881959Swnj 1891959Swnj /* 1901959Swnj * The argument is a 0-origin day number. 1911959Swnj * The value is the day number of the first 1921959Swnj * Sunday on or after the day. 1931959Swnj */ 1941959Swnj static 1951959Swnj sunday(t, d) 1961959Swnj register struct tm *t; 1971959Swnj register int d; 1981959Swnj { 1991959Swnj if (d >= 58) 2001959Swnj d += dysize(t->tm_year) - 365; 2011959Swnj return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 2021959Swnj } 2031959Swnj 2041959Swnj struct tm * 2051959Swnj gmtime(tim) 20612974Ssam unsigned long *tim; 2071959Swnj { 2081959Swnj register int d0, d1; 20912974Ssam unsigned long hms, day; 2101959Swnj register int *tp; 2111959Swnj static struct tm xtime; 2121959Swnj 2131959Swnj /* 2141959Swnj * break initial number into days 2151959Swnj */ 2161959Swnj hms = *tim % 86400; 2171959Swnj day = *tim / 86400; 2181959Swnj if (hms<0) { 2191959Swnj hms += 86400; 2201959Swnj day -= 1; 2211959Swnj } 2221959Swnj tp = (int *)&xtime; 2231959Swnj 2241959Swnj /* 2251959Swnj * generate hours:minutes:seconds 2261959Swnj */ 2271959Swnj *tp++ = hms%60; 2281959Swnj d1 = hms/60; 2291959Swnj *tp++ = d1%60; 2301959Swnj d1 /= 60; 2311959Swnj *tp++ = d1; 2321959Swnj 2331959Swnj /* 2341959Swnj * day is the day number. 2351959Swnj * generate day of the week. 2361959Swnj * The addend is 4 mod 7 (1/1/1970 was Thursday) 2371959Swnj */ 2381959Swnj 2391959Swnj xtime.tm_wday = (day+7340036)%7; 2401959Swnj 2411959Swnj /* 2421959Swnj * year number 2431959Swnj */ 2441959Swnj if (day>=0) for(d1=70; day >= dysize(d1); d1++) 2451959Swnj day -= dysize(d1); 2461959Swnj else for (d1=70; day<0; d1--) 2471959Swnj day += dysize(d1-1); 2481959Swnj xtime.tm_year = d1; 2491959Swnj xtime.tm_yday = d0 = day; 2501959Swnj 2511959Swnj /* 2521959Swnj * generate month 2531959Swnj */ 2541959Swnj 2551959Swnj if (dysize(d1)==366) 2561959Swnj dmsize[1] = 29; 2571959Swnj for(d1=0; d0 >= dmsize[d1]; d1++) 2581959Swnj d0 -= dmsize[d1]; 2591959Swnj dmsize[1] = 28; 2601959Swnj *tp++ = d0+1; 2611959Swnj *tp++ = d1; 2621959Swnj xtime.tm_isdst = 0; 2631959Swnj return(&xtime); 2641959Swnj } 2651959Swnj 2661959Swnj char * 2671959Swnj asctime(t) 2681959Swnj struct tm *t; 2691959Swnj { 2701959Swnj register char *cp, *ncp; 2711959Swnj register int *tp; 2721959Swnj 2731959Swnj cp = cbuf; 2741959Swnj for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 2751959Swnj ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 2761959Swnj cp = cbuf; 2771959Swnj *cp++ = *ncp++; 2781959Swnj *cp++ = *ncp++; 2791959Swnj *cp++ = *ncp++; 2801959Swnj cp++; 2811959Swnj tp = &t->tm_mon; 2821959Swnj ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 2831959Swnj *cp++ = *ncp++; 2841959Swnj *cp++ = *ncp++; 2851959Swnj *cp++ = *ncp++; 2861959Swnj cp = ct_numb(cp, *--tp); 2871959Swnj cp = ct_numb(cp, *--tp+100); 2881959Swnj cp = ct_numb(cp, *--tp+100); 2891959Swnj cp = ct_numb(cp, *--tp+100); 2901959Swnj if (t->tm_year>=100) { 2911959Swnj cp[1] = '2'; 29212974Ssam cp[2] = '0' + t->tm_year >= 200; 2931959Swnj } 2941959Swnj cp += 2; 2951959Swnj cp = ct_numb(cp, t->tm_year+100); 2961959Swnj return(cbuf); 2971959Swnj } 2981959Swnj 2991959Swnj dysize(y) 3001959Swnj { 3011959Swnj if((y%4) == 0) 3021959Swnj return(366); 3031959Swnj return(365); 3041959Swnj } 3051959Swnj 3061959Swnj static char * 3071959Swnj ct_numb(cp, n) 3081959Swnj register char *cp; 3091959Swnj { 3101959Swnj cp++; 3111959Swnj if (n>=10) 3121959Swnj *cp++ = (n/10)%10 + '0'; 3131959Swnj else 3141959Swnj *cp++ = ' '; 3151959Swnj *cp++ = n%10 + '0'; 3161959Swnj return(cp); 3171959Swnj } 318