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*25299Smckusick static char sccsid[] = "@(#)ctime.c 5.3 (Berkeley) 10/25/85"; 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; 16212974Ssam struct timezone zone; 1631959Swnj 16412974Ssam gettimeofday(&curtime, &zone); 16517054Sralph copyt = *tim - (time_t)zone.tz_minuteswest*60; 1661959Swnj ct = gmtime(©t); 1671959Swnj dayno = ct->tm_yday; 16812974Ssam for (dr = dayrules; dr->dst_type >= 0; dr++) 16912974Ssam if (dr->dst_type == zone.tz_dsttime) 17012974Ssam break; 17112974Ssam if (dr->dst_type >= 0) { 17212974Ssam year = ct->tm_year + 1900; 17312974Ssam for (ds = dr->dst_rules; ds->dayyr; ds++) 17412974Ssam if (ds->dayyr == year) 17512974Ssam break; 17612974Ssam dalybeg = ds->daylb; /* first Sun after dst starts */ 17712974Ssam daylend = ds->dayle; /* first Sun after dst ends */ 17812974Ssam dalybeg = sunday(ct, dalybeg); 17912974Ssam daylend = sunday(ct, daylend); 18012974Ssam switch (dr->dst_hemi) { 18112974Ssam case NTH: 18212974Ssam if (!( 18312974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) && 18412974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<1)) 18512974Ssam )) 18612974Ssam return(ct); 18712974Ssam break; 18812974Ssam case STH: 18912974Ssam if (!( 19012974Ssam (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) || 19112974Ssam (dayno<daylend || (dayno==daylend && ct->tm_hour<2)) 19212974Ssam )) 19312974Ssam return(ct); 19412974Ssam break; 19512974Ssam default: 19612974Ssam return(ct); 19712974Ssam } 19812974Ssam copyt += dr->dst_hrs*60*60; 1991959Swnj ct = gmtime(©t); 2001959Swnj ct->tm_isdst++; 2011959Swnj } 2021959Swnj return(ct); 2031959Swnj } 2041959Swnj 2051959Swnj /* 2061959Swnj * The argument is a 0-origin day number. 207*25299Smckusick * The value is the day number of the last 20823720Skre * Sunday on or before the day. 2091959Swnj */ 2101959Swnj static 2111959Swnj sunday(t, d) 2121959Swnj register struct tm *t; 2131959Swnj register int d; 2141959Swnj { 2151959Swnj if (d >= 58) 2161959Swnj d += dysize(t->tm_year) - 365; 2171959Swnj return(d - (d - t->tm_yday + t->tm_wday + 700) % 7); 2181959Swnj } 2191959Swnj 2201959Swnj struct tm * 2211959Swnj gmtime(tim) 22217054Sralph time_t *tim; 2231959Swnj { 2241959Swnj register int d0, d1; 22516197Skarels long hms, day; 2261959Swnj register int *tp; 2271959Swnj static struct tm xtime; 2281959Swnj 2291959Swnj /* 2301959Swnj * break initial number into days 2311959Swnj */ 2321959Swnj hms = *tim % 86400; 2331959Swnj day = *tim / 86400; 2341959Swnj if (hms<0) { 2351959Swnj hms += 86400; 2361959Swnj day -= 1; 2371959Swnj } 2381959Swnj tp = (int *)&xtime; 2391959Swnj 2401959Swnj /* 2411959Swnj * generate hours:minutes:seconds 2421959Swnj */ 2431959Swnj *tp++ = hms%60; 2441959Swnj d1 = hms/60; 2451959Swnj *tp++ = d1%60; 2461959Swnj d1 /= 60; 2471959Swnj *tp++ = d1; 2481959Swnj 2491959Swnj /* 2501959Swnj * day is the day number. 2511959Swnj * generate day of the week. 2521959Swnj * The addend is 4 mod 7 (1/1/1970 was Thursday) 2531959Swnj */ 2541959Swnj 2551959Swnj xtime.tm_wday = (day+7340036)%7; 2561959Swnj 2571959Swnj /* 2581959Swnj * year number 2591959Swnj */ 2601959Swnj if (day>=0) for(d1=70; day >= dysize(d1); d1++) 2611959Swnj day -= dysize(d1); 2621959Swnj else for (d1=70; day<0; d1--) 2631959Swnj day += dysize(d1-1); 2641959Swnj xtime.tm_year = d1; 2651959Swnj xtime.tm_yday = d0 = day; 2661959Swnj 2671959Swnj /* 2681959Swnj * generate month 2691959Swnj */ 2701959Swnj 2711959Swnj if (dysize(d1)==366) 2721959Swnj dmsize[1] = 29; 2731959Swnj for(d1=0; d0 >= dmsize[d1]; d1++) 2741959Swnj d0 -= dmsize[d1]; 2751959Swnj dmsize[1] = 28; 2761959Swnj *tp++ = d0+1; 2771959Swnj *tp++ = d1; 2781959Swnj xtime.tm_isdst = 0; 2791959Swnj return(&xtime); 2801959Swnj } 2811959Swnj 2821959Swnj char * 2831959Swnj asctime(t) 2841959Swnj struct tm *t; 2851959Swnj { 2861959Swnj register char *cp, *ncp; 2871959Swnj register int *tp; 2881959Swnj 2891959Swnj cp = cbuf; 2901959Swnj for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;); 2911959Swnj ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday]; 2921959Swnj cp = cbuf; 2931959Swnj *cp++ = *ncp++; 2941959Swnj *cp++ = *ncp++; 2951959Swnj *cp++ = *ncp++; 2961959Swnj cp++; 2971959Swnj tp = &t->tm_mon; 2981959Swnj ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3]; 2991959Swnj *cp++ = *ncp++; 3001959Swnj *cp++ = *ncp++; 3011959Swnj *cp++ = *ncp++; 3021959Swnj cp = ct_numb(cp, *--tp); 3031959Swnj cp = ct_numb(cp, *--tp+100); 3041959Swnj cp = ct_numb(cp, *--tp+100); 3051959Swnj cp = ct_numb(cp, *--tp+100); 3061959Swnj if (t->tm_year>=100) { 3071959Swnj cp[1] = '2'; 30817054Sralph cp[2] = '0' + (t->tm_year-100) / 100; 3091959Swnj } 3101959Swnj cp += 2; 3111959Swnj cp = ct_numb(cp, t->tm_year+100); 3121959Swnj return(cbuf); 3131959Swnj } 3141959Swnj 3151959Swnj dysize(y) 3161959Swnj { 3171959Swnj if((y%4) == 0) 3181959Swnj return(366); 3191959Swnj return(365); 3201959Swnj } 3211959Swnj 3221959Swnj static char * 3231959Swnj ct_numb(cp, n) 3241959Swnj register char *cp; 3251959Swnj { 3261959Swnj cp++; 3271959Swnj if (n>=10) 3281959Swnj *cp++ = (n/10)%10 + '0'; 3291959Swnj else 3301959Swnj *cp++ = ' '; 3311959Swnj *cp++ = n%10 + '0'; 3321959Swnj return(cp); 3331959Swnj } 334