122084Smckusick /* 222084Smckusick * Copyright (c) 1980 Regents of the University of California. 322084Smckusick * All rights reserved. The Berkeley software License Agreement 422084Smckusick * specifies the terms and conditions for redistribution. 522084Smckusick */ 622084Smckusick 713582Ssam #ifndef lint 8*25662Sbloom static char sccsid[] = "@(#)ctime.c 5.4 (Berkeley) 01/03/86"; 922084Smckusick #endif not lint 1022084Smckusick 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: 9223720Skre * WE: Great Britain, Portugal? 9313876Ssam * ME: Belgium, Luxembourg, Netherlands, Denmark, Norway, 9413876Ssam * Austria, Poland, Czechoslovakia, Sweden, Switzerland, 9513876Ssam * DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia 9623720Skre * Finland (EE timezone, but ME dst rules) 9713876Ssam * Eastern European dst is unknown, we'll make it ME until someone speaks up. 9823720Skre * EE: Bulgaria, Greece, Rumania, Turkey, Western Russia 9923720Skre * 10023720Skre * Ireland is unpredictable. (Years when Easter Sunday just happens ...) 10123720Skre * Years before 1983 are suspect. 10213876Ssam */ 10313876Ssam static struct dstab wedaytab[] = { 10423720Skre 1983, 89, 296, /* 1983: end March - end Oct */ 10523720Skre 0, 89, 303, /* others: end March - end Oct */ 10613876Ssam }; 10713876Ssam 10813876Ssam static struct dstab medaytab[] = { 10923720Skre 1983, 89, 296, /* 1983: end March - end Oct */ 11023720Skre 0, 89, 272, /* others: end March - end Sep */ 11113876Ssam }; 11213876Ssam 11323720Skre /* 11423720Skre * Canada, same as the US, except no early 70's fluctuations. 11523720Skre * Can this really be right ?? 11623720Skre */ 11723720Skre static struct dstab candaytab[] = { 11823720Skre 0, 119, 303, /* all years: end Apr - end Oct */ 11923720Skre }; 12023720Skre 12112974Ssam static struct dayrules { 12212974Ssam int dst_type; /* number obtained from system */ 12312974Ssam int dst_hrs; /* hours to add when dst on */ 12412974Ssam struct dstab * dst_rules; /* one of the above */ 12512974Ssam enum {STH,NTH} dst_hemi; /* southern, northern hemisphere */ 12612974Ssam } dayrules [] = { 12712974Ssam DST_USA, 1, usdaytab, NTH, 12812974Ssam DST_AUST, 1, ausdaytab, STH, 12913876Ssam DST_WET, 1, wedaytab, NTH, 13013876Ssam DST_MET, 1, medaytab, NTH, 13113876Ssam DST_EET, 1, medaytab, NTH, /* XXX */ 13223720Skre DST_CAN, 1, candaytab, NTH, 13312974Ssam -1, 13412974Ssam }; 13512974Ssam 1361959Swnj struct tm *gmtime(); 1371959Swnj char *ct_numb(); 1381959Swnj struct tm *localtime(); 1391959Swnj char *ctime(); 1401959Swnj char *ct_num(); 1411959Swnj char *asctime(); 1421959Swnj 1431959Swnj char * 1441959Swnj ctime(t) 14517054Sralph time_t *t; 1461959Swnj { 1471959Swnj return(asctime(localtime(t))); 1481959Swnj } 1491959Swnj 1501959Swnj struct tm * 1511959Swnj localtime(tim) 15217054Sralph time_t *tim; 1531959Swnj { 1541959Swnj register int dayno; 1551959Swnj register struct tm *ct; 15612974Ssam register dalybeg, daylend; 15712974Ssam register struct dayrules *dr; 15812974Ssam register struct dstab *ds; 15912974Ssam int year; 16017054Sralph time_t copyt; 16112974Ssam struct timeval curtime; 162*25662Sbloom static struct timezone zone; 163*25662Sbloom static int init = 0; 1641959Swnj 165*25662Sbloom if (!init) { 166*25662Sbloom gettimeofday(&curtime, &zone); 167*25662Sbloom init++; 168*25662Sbloom } 16917054Sralph copyt = *tim - (time_t)zone.tz_minuteswest*60; 1701959Swnj ct = gmtime(©t); 1711959Swnj dayno = ct->tm_yday; 17212974Ssam for (dr = dayrules; dr->dst_type >= 0; dr++) 17312974Ssam if (dr->dst_type == zone.tz_dsttime) 17412974Ssam break; 17512974Ssam if (dr->dst_type >= 0) { 17612974Ssam year = ct->tm_year + 1900; 17712974Ssam for (ds = dr->dst_rules; ds->dayyr; ds++) 17812974Ssam if (ds->dayyr == year) 17912974Ssam break; 18012974Ssam dalybeg = ds->daylb; /* first Sun after dst starts */ 18112974Ssam daylend = ds->dayle; /* first Sun after dst ends */ 18212974Ssam dalybeg = sunday(ct, dalybeg); 18312974Ssam daylend = sunday(ct, daylend); 18412974Ssam switch (dr->dst_hemi) { 18512974Ssam case NTH: 18612974Ssam if (!( 18712974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 18812974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 18912974Ssam )) 19012974Ssam return(ct); 19112974Ssam break; 19212974Ssam case STH: 19312974Ssam if (!( 19412974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 19512974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 19612974Ssam )) 19712974Ssam return(ct); 19812974Ssam break; 19912974Ssam default: 20012974Ssam return(ct); 20112974Ssam } 20212974Ssam copyt += dr->dst_hrs*60*60; 2031959Swnj ct = gmtime(©t); 2041959Swnj ct->tm_isdst++; 2051959Swnj } 2061959Swnj return(ct); 2071959Swnj } 2081959Swnj 2091959Swnj /* 2101959Swnj * The argument is a 0-origin day number. 21125299Smckusick * The value is the day number of the last 21223720Skre * Sunday on or before the day. 2131959Swnj */ 2141959Swnj static 2151959Swnj sunday(t, d) 2161959Swnj register struct tm *t; 2171959Swnj register int d; 2181959Swnj { 2191959Swnj if (d >= 58) 2201959Swnj d += dysize(t->tm_year) - 365; 2211959Swnj return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 2221959Swnj } 2231959Swnj 2241959Swnj struct tm * 2251959Swnj gmtime(tim) 22617054Sralph time_t *tim; 2271959Swnj { 2281959Swnj register int d0, d1; 22916197Skarels long hms, day; 2301959Swnj register int *tp; 2311959Swnj static struct tm xtime; 2321959Swnj 2331959Swnj /* 2341959Swnj * break initial number into days 2351959Swnj */ 2361959Swnj hms = *tim % 86400; 2371959Swnj day = *tim / 86400; 2381959Swnj if (hms<0) { 2391959Swnj hms += 86400; 2401959Swnj day -= 1; 2411959Swnj } 2421959Swnj tp = (int *)&xtime; 2431959Swnj 2441959Swnj /* 2451959Swnj * generate hours:minutes:seconds 2461959Swnj */ 2471959Swnj *tp++ = hms%60; 2481959Swnj d1 = hms/60; 2491959Swnj *tp++ = d1%60; 2501959Swnj d1 /= 60; 2511959Swnj *tp++ = d1; 2521959Swnj 2531959Swnj /* 2541959Swnj * day is the day number. 2551959Swnj * generate day of the week. 2561959Swnj * The addend is 4 mod 7 (1/1/1970 was Thursday) 2571959Swnj */ 2581959Swnj 2591959Swnj xtime.tm_wday = (day+7340036)%7; 2601959Swnj 2611959Swnj /* 2621959Swnj * year number 2631959Swnj */ 2641959Swnj if (day>=0) for(d1=70; day >= dysize(d1); d1++) 2651959Swnj day -= dysize(d1); 2661959Swnj else for (d1=70; day<0; d1--) 2671959Swnj day += dysize(d1-1); 2681959Swnj xtime.tm_year = d1; 2691959Swnj xtime.tm_yday = d0 = day; 2701959Swnj 2711959Swnj /* 2721959Swnj * generate month 2731959Swnj */ 2741959Swnj 2751959Swnj if (dysize(d1)==366) 2761959Swnj dmsize[1] = 29; 2771959Swnj for(d1=0; d0 >= dmsize[d1]; d1++) 2781959Swnj d0 -= dmsize[d1]; 2791959Swnj dmsize[1] = 28; 2801959Swnj *tp++ = d0+1; 2811959Swnj *tp++ = d1; 2821959Swnj xtime.tm_isdst = 0; 2831959Swnj return(&xtime); 2841959Swnj } 2851959Swnj 2861959Swnj char * 2871959Swnj asctime(t) 2881959Swnj struct tm *t; 2891959Swnj { 2901959Swnj register char *cp, *ncp; 2911959Swnj register int *tp; 2921959Swnj 2931959Swnj cp = cbuf; 2941959Swnj for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 2951959Swnj ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 2961959Swnj cp = cbuf; 2971959Swnj *cp++ = *ncp++; 2981959Swnj *cp++ = *ncp++; 2991959Swnj *cp++ = *ncp++; 3001959Swnj cp++; 3011959Swnj tp = &t->tm_mon; 3021959Swnj ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 3031959Swnj *cp++ = *ncp++; 3041959Swnj *cp++ = *ncp++; 3051959Swnj *cp++ = *ncp++; 3061959Swnj cp = ct_numb(cp, *--tp); 3071959Swnj cp = ct_numb(cp, *--tp+100); 3081959Swnj cp = ct_numb(cp, *--tp+100); 3091959Swnj cp = ct_numb(cp, *--tp+100); 3101959Swnj if (t->tm_year>=100) { 3111959Swnj cp[1] = '2'; 31217054Sralph cp[2] = '0' + (t->tm_year-100) / 100; 3131959Swnj } 3141959Swnj cp += 2; 3151959Swnj cp = ct_numb(cp, t->tm_year+100); 3161959Swnj return(cbuf); 3171959Swnj } 3181959Swnj 3191959Swnj dysize(y) 3201959Swnj { 3211959Swnj if((y%4) == 0) 3221959Swnj return(366); 3231959Swnj return(365); 3241959Swnj } 3251959Swnj 3261959Swnj static char * 3271959Swnj ct_numb(cp, n) 3281959Swnj register char *cp; 3291959Swnj { 3301959Swnj cp++; 3311959Swnj if (n>=10) 3321959Swnj *cp++ = (n/10)%10 + '0'; 3331959Swnj else 3341959Swnj *cp++ = ' '; 3351959Swnj *cp++ = n%10 + '0'; 3361959Swnj return(cp); 3371959Swnj } 338