1*22084Smckusick /* 2*22084Smckusick * Copyright (c) 1980 Regents of the University of California. 3*22084Smckusick * All rights reserved. The Berkeley software License Agreement 4*22084Smckusick * specifies the terms and conditions for redistribution. 5*22084Smckusick */ 6*22084Smckusick 713582Ssam #ifndef lint 8*22084Smckusick static char sccsid[] = "@(#)ctime.c 5.1 (Berkeley) 06/05/85"; 9*22084Smckusick #endif not lint 10*22084Smckusick 111959Swnj /* 121959Swnj * This routine converts time as follows. 131959Swnj * The epoch is 0000 Jan 1 1970 GMT. 141959Swnj * The argument time is in seconds since then. 151959Swnj * The localtime(t) entry returns a pointer to an array 161959Swnj * containing 171959Swnj * seconds (0-59) 181959Swnj * minutes (0-59) 191959Swnj * hours (0-23) 201959Swnj * day of month (1-31) 211959Swnj * month (0-11) 221959Swnj * year-1970 231959Swnj * weekday (0-6, Sun is 0) 241959Swnj * day of the year 251959Swnj * daylight savings flag 261959Swnj * 271959Swnj * The routine calls the system to determine the local 281959Swnj * timezone and whether Daylight Saving Time is permitted locally. 2913876Ssam * (DST is then determined by the current local rules) 301959Swnj * 311959Swnj * The routine does not work 321959Swnj * in Saudi Arabia which runs on Solar time. 331959Swnj * 341959Swnj * asctime(tvec)) 351959Swnj * where tvec is produced by localtime 361959Swnj * returns a ptr to a character string 371959Swnj * that has the ascii time in the form 3817054Sralph * Thu Jan 01 00:00:00 1970\n\0 3917054Sralph * 0123456789012345678901234 5 401959Swnj * 0 1 2 411959Swnj * 421959Swnj * ctime(t) just calls localtime, then asctime. 431959Swnj */ 441959Swnj 4513582Ssam #include <sys/time.h> 461959Swnj #include <sys/types.h> 471959Swnj #include <sys/timeb.h> 481959Swnj 491959Swnj static char cbuf[26]; 501959Swnj static int dmsize[12] = 511959Swnj { 521959Swnj 31, 531959Swnj 28, 541959Swnj 31, 551959Swnj 30, 561959Swnj 31, 571959Swnj 30, 581959Swnj 31, 591959Swnj 31, 601959Swnj 30, 611959Swnj 31, 621959Swnj 30, 631959Swnj 31 641959Swnj }; 651959Swnj 661959Swnj /* 671959Swnj * The following table is used for 1974 and 1975 and 681959Swnj * gives the day number of the first day after the Sunday of the 691959Swnj * change. 701959Swnj */ 7112974Ssam struct dstab { 7212974Ssam int dayyr; 731959Swnj int daylb; 741959Swnj int dayle; 751959Swnj }; 761959Swnj 7712974Ssam static struct dstab usdaytab[] = { 7812974Ssam 1974, 5, 333, /* 1974: Jan 6 - last Sun. in Nov */ 7912974Ssam 1975, 58, 303, /* 1975: Last Sun. in Feb - last Sun in Oct */ 8012974Ssam 0, 119, 303, /* all other years: end Apr - end Oct */ 8112974Ssam }; 8212974Ssam static struct dstab ausdaytab[] = { 8312974Ssam 1970, 400, 0, /* 1970: no daylight saving at all */ 8412974Ssam 1971, 303, 0, /* 1971: daylight saving from Oct 31 */ 8512974Ssam 1972, 303, 58, /* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */ 8612974Ssam 0, 303, 65, /* others: -> Mar 7, Oct 31 -> */ 8712974Ssam }; 8812974Ssam 8913876Ssam /* 9013876Ssam * The European tables ... based on hearsay 9113876Ssam * Believed correct for: 9213876Ssam * WE: Great Britain, Ireland, Portugal 9313876Ssam * ME: Belgium, Luxembourg, Netherlands, Denmark, Norway, 9413876Ssam * Austria, Poland, Czechoslovakia, Sweden, Switzerland, 9513876Ssam * DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia 9613876Ssam * Eastern European dst is unknown, we'll make it ME until someone speaks up. 9713876Ssam * EE: Bulgaria, Finland, Greece, Rumania, Turkey, Western Russia 9813876Ssam */ 9913876Ssam static struct dstab wedaytab[] = { 10013876Ssam 1983, 86, 303, /* 1983: end March - end Oct */ 10113876Ssam 1984, 86, 303, /* 1984: end March - end Oct */ 10213876Ssam 1985, 86, 303, /* 1985: end March - end Oct */ 10313876Ssam 0, 400, 0, /* others: no daylight saving at all ??? */ 10413876Ssam }; 10513876Ssam 10613876Ssam static struct dstab medaytab[] = { 10713876Ssam 1983, 86, 272, /* 1983: end March - end Sep */ 10813876Ssam 1984, 86, 272, /* 1984: end March - end Sep */ 10913876Ssam 1985, 86, 272, /* 1985: end March - end Sep */ 11013876Ssam 0, 400, 0, /* others: no daylight saving at all ??? */ 11113876Ssam }; 11213876Ssam 11312974Ssam static struct dayrules { 11412974Ssam int dst_type; /* number obtained from system */ 11512974Ssam int dst_hrs; /* hours to add when dst on */ 11612974Ssam struct dstab * dst_rules; /* one of the above */ 11712974Ssam enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */ 11812974Ssam } dayrules [] = { 11912974Ssam DST_USA, 1, usdaytab, NTH, 12012974Ssam DST_AUST, 1, ausdaytab, STH, 12113876Ssam DST_WET, 1, wedaytab, NTH, 12213876Ssam DST_MET, 1, medaytab, NTH, 12313876Ssam DST_EET, 1, medaytab, NTH, /* XXX */ 12412974Ssam -1, 12512974Ssam }; 12612974Ssam 1271959Swnj struct tm *gmtime(); 1281959Swnj char *ct_numb(); 1291959Swnj struct tm *localtime(); 1301959Swnj char *ctime(); 1311959Swnj char *ct_num(); 1321959Swnj char *asctime(); 1331959Swnj 1341959Swnj char * 1351959Swnj ctime(t) 13617054Sralph time_t *t; 1371959Swnj { 1381959Swnj return(asctime(localtime(t))); 1391959Swnj } 1401959Swnj 1411959Swnj struct tm * 1421959Swnj localtime(tim) 14317054Sralph time_t *tim; 1441959Swnj { 1451959Swnj register int dayno; 1461959Swnj register struct tm *ct; 14712974Ssam register dalybeg, daylend; 14812974Ssam register struct dayrules *dr; 14912974Ssam register struct dstab *ds; 15012974Ssam int year; 15117054Sralph time_t copyt; 15212974Ssam struct timeval curtime; 15312974Ssam struct timezone zone; 1541959Swnj 15512974Ssam gettimeofday(&curtime, &zone); 15617054Sralph copyt = *tim - (time_t)zone.tz_minuteswest*60; 1571959Swnj ct = gmtime(©t); 1581959Swnj dayno = ct->tm_yday; 15912974Ssam for (dr = dayrules; dr->dst_type >= 0; dr++) 16012974Ssam if (dr->dst_type == zone.tz_dsttime) 16112974Ssam break; 16212974Ssam if (dr->dst_type >= 0) { 16312974Ssam year = ct->tm_year + 1900; 16412974Ssam for (ds = dr->dst_rules; ds->dayyr; ds++) 16512974Ssam if (ds->dayyr == year) 16612974Ssam break; 16712974Ssam dalybeg = ds->daylb; /* first Sun after dst starts */ 16812974Ssam daylend = ds->dayle; /* first Sun after dst ends */ 16912974Ssam dalybeg = sunday(ct, dalybeg); 17012974Ssam daylend = sunday(ct, daylend); 17112974Ssam switch (dr->dst_hemi) { 17212974Ssam case NTH: 17312974Ssam if (!( 17412974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 17512974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 17612974Ssam )) 17712974Ssam return(ct); 17812974Ssam break; 17912974Ssam case STH: 18012974Ssam if (!( 18112974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 18212974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 18312974Ssam )) 18412974Ssam return(ct); 18512974Ssam break; 18612974Ssam default: 18712974Ssam return(ct); 18812974Ssam } 18912974Ssam copyt += dr->dst_hrs*60*60; 1901959Swnj ct = gmtime(©t); 1911959Swnj ct->tm_isdst++; 1921959Swnj } 1931959Swnj return(ct); 1941959Swnj } 1951959Swnj 1961959Swnj /* 1971959Swnj * The argument is a 0-origin day number. 1981959Swnj * The value is the day number of the first 1991959Swnj * Sunday on or after the day. 2001959Swnj */ 2011959Swnj static 2021959Swnj sunday(t, d) 2031959Swnj register struct tm *t; 2041959Swnj register int d; 2051959Swnj { 2061959Swnj if (d >= 58) 2071959Swnj d += dysize(t->tm_year) - 365; 2081959Swnj return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 2091959Swnj } 2101959Swnj 2111959Swnj struct tm * 2121959Swnj gmtime(tim) 21317054Sralph time_t *tim; 2141959Swnj { 2151959Swnj register int d0, d1; 21616197Skarels long hms, day; 2171959Swnj register int *tp; 2181959Swnj static struct tm xtime; 2191959Swnj 2201959Swnj /* 2211959Swnj * break initial number into days 2221959Swnj */ 2231959Swnj hms = *tim % 86400; 2241959Swnj day = *tim / 86400; 2251959Swnj if (hms<0) { 2261959Swnj hms += 86400; 2271959Swnj day -= 1; 2281959Swnj } 2291959Swnj tp = (int *)&xtime; 2301959Swnj 2311959Swnj /* 2321959Swnj * generate hours:minutes:seconds 2331959Swnj */ 2341959Swnj *tp++ = hms%60; 2351959Swnj d1 = hms/60; 2361959Swnj *tp++ = d1%60; 2371959Swnj d1 /= 60; 2381959Swnj *tp++ = d1; 2391959Swnj 2401959Swnj /* 2411959Swnj * day is the day number. 2421959Swnj * generate day of the week. 2431959Swnj * The addend is 4 mod 7 (1/1/1970 was Thursday) 2441959Swnj */ 2451959Swnj 2461959Swnj xtime.tm_wday = (day+7340036)%7; 2471959Swnj 2481959Swnj /* 2491959Swnj * year number 2501959Swnj */ 2511959Swnj if (day>=0) for(d1=70; day >= dysize(d1); d1++) 2521959Swnj day -= dysize(d1); 2531959Swnj else for (d1=70; day<0; d1--) 2541959Swnj day += dysize(d1-1); 2551959Swnj xtime.tm_year = d1; 2561959Swnj xtime.tm_yday = d0 = day; 2571959Swnj 2581959Swnj /* 2591959Swnj * generate month 2601959Swnj */ 2611959Swnj 2621959Swnj if (dysize(d1)==366) 2631959Swnj dmsize[1] = 29; 2641959Swnj for(d1=0; d0 >= dmsize[d1]; d1++) 2651959Swnj d0 -= dmsize[d1]; 2661959Swnj dmsize[1] = 28; 2671959Swnj *tp++ = d0+1; 2681959Swnj *tp++ = d1; 2691959Swnj xtime.tm_isdst = 0; 2701959Swnj return(&xtime); 2711959Swnj } 2721959Swnj 2731959Swnj char * 2741959Swnj asctime(t) 2751959Swnj struct tm *t; 2761959Swnj { 2771959Swnj register char *cp, *ncp; 2781959Swnj register int *tp; 2791959Swnj 2801959Swnj cp = cbuf; 2811959Swnj for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 2821959Swnj ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 2831959Swnj cp = cbuf; 2841959Swnj *cp++ = *ncp++; 2851959Swnj *cp++ = *ncp++; 2861959Swnj *cp++ = *ncp++; 2871959Swnj cp++; 2881959Swnj tp = &t->tm_mon; 2891959Swnj ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 2901959Swnj *cp++ = *ncp++; 2911959Swnj *cp++ = *ncp++; 2921959Swnj *cp++ = *ncp++; 2931959Swnj cp = ct_numb(cp, *--tp); 2941959Swnj cp = ct_numb(cp, *--tp+100); 2951959Swnj cp = ct_numb(cp, *--tp+100); 2961959Swnj cp = ct_numb(cp, *--tp+100); 2971959Swnj if (t->tm_year>=100) { 2981959Swnj cp[1] = '2'; 29917054Sralph cp[2] = '0' + (t->tm_year-100) / 100; 3001959Swnj } 3011959Swnj cp += 2; 3021959Swnj cp = ct_numb(cp, t->tm_year+100); 3031959Swnj return(cbuf); 3041959Swnj } 3051959Swnj 3061959Swnj dysize(y) 3071959Swnj { 3081959Swnj if((y%4) == 0) 3091959Swnj return(366); 3101959Swnj return(365); 3111959Swnj } 3121959Swnj 3131959Swnj static char * 3141959Swnj ct_numb(cp, n) 3151959Swnj register char *cp; 3161959Swnj { 3171959Swnj cp++; 3181959Swnj if (n>=10) 3191959Swnj *cp++ = (n/10)%10 + '0'; 3201959Swnj else 3211959Swnj *cp++ = ' '; 3221959Swnj *cp++ = n%10 + '0'; 3231959Swnj return(cp); 3241959Swnj } 325