xref: /csrg-svn/lib/libc/gen/ctime.c (revision 12974)
1*12974Ssam /* @(#)ctime.c	4.2 (Berkeley) 06/10/83 */
21959Swnj /*
31959Swnj  * This routine converts time as follows.
41959Swnj  * The epoch is 0000 Jan 1 1970 GMT.
51959Swnj  * The argument time is in seconds since then.
61959Swnj  * The localtime(t) entry returns a pointer to an array
71959Swnj  * containing
81959Swnj  *  seconds (0-59)
91959Swnj  *  minutes (0-59)
101959Swnj  *  hours (0-23)
111959Swnj  *  day of month (1-31)
121959Swnj  *  month (0-11)
131959Swnj  *  year-1970
141959Swnj  *  weekday (0-6, Sun is 0)
151959Swnj  *  day of the year
161959Swnj  *  daylight savings flag
171959Swnj  *
181959Swnj  * The routine calls the system to determine the local
191959Swnj  * timezone and whether Daylight Saving Time is permitted locally.
201959Swnj  * (DST is then determined by the current US standard rules)
211959Swnj  * There is a table that accounts for the peculiarities
221959Swnj  * undergone by daylight time in 1974-1975.
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 
381959Swnj #include <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  */
64*12974Ssam struct dstab {
65*12974Ssam 	int	dayyr;
661959Swnj 	int	daylb;
671959Swnj 	int	dayle;
681959Swnj };
691959Swnj 
70*12974Ssam static struct dstab usdaytab[] = {
71*12974Ssam 	1974,	5,	333,	/* 1974: Jan 6 - last Sun. in Nov */
72*12974Ssam 	1975,	58,	303,	/* 1975: Last Sun. in Feb - last Sun in Oct */
73*12974Ssam 	0,	119,	303,	/* all other years: end Apr - end Oct */
74*12974Ssam };
75*12974Ssam static struct dstab ausdaytab[] = {
76*12974Ssam 	1970,	400,	0,	/* 1970: no daylight saving at all */
77*12974Ssam 	1971,	303,	0,	/* 1971: daylight saving from Oct 31 */
78*12974Ssam 	1972,	303,	58,	/* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */
79*12974Ssam 	0,	303,	65,	/* others: -> Mar 7, Oct 31 -> */
80*12974Ssam };
81*12974Ssam 
82*12974Ssam static struct dayrules {
83*12974Ssam 	int		dst_type;	/* number obtained from system */
84*12974Ssam 	int		dst_hrs;	/* hours to add when dst on */
85*12974Ssam 	struct	dstab *	dst_rules;	/* one of the above */
86*12974Ssam 	enum {STH,NTH}	dst_hemi;	/* southern, northern hemisphere */
87*12974Ssam } dayrules [] = {
88*12974Ssam 	DST_USA,	1,	usdaytab,	NTH,
89*12974Ssam 	DST_AUST,	1,	ausdaytab,	STH,
90*12974Ssam 	-1,
91*12974Ssam };
92*12974Ssam 
931959Swnj struct tm	*gmtime();
941959Swnj char		*ct_numb();
951959Swnj struct tm	*localtime();
961959Swnj char	*ctime();
971959Swnj char	*ct_num();
981959Swnj char	*asctime();
991959Swnj 
1001959Swnj char *
1011959Swnj ctime(t)
102*12974Ssam unsigned long *t;
1031959Swnj {
1041959Swnj 	return(asctime(localtime(t)));
1051959Swnj }
1061959Swnj 
1071959Swnj struct tm *
1081959Swnj localtime(tim)
109*12974Ssam unsigned long *tim;
1101959Swnj {
1111959Swnj 	register int dayno;
1121959Swnj 	register struct tm *ct;
113*12974Ssam 	register dalybeg, daylend;
114*12974Ssam 	register struct dayrules *dr;
115*12974Ssam 	register struct dstab *ds;
116*12974Ssam 	int year;
117*12974Ssam 	unsigned long copyt;
118*12974Ssam 	struct timeval curtime;
119*12974Ssam 	struct timezone zone;
1201959Swnj 
121*12974Ssam 	gettimeofday(&curtime, &zone);
122*12974Ssam 	copyt = *tim - (unsigned long)zone.tz_minuteswest*60;
1231959Swnj 	ct = gmtime(&copyt);
1241959Swnj 	dayno = ct->tm_yday;
125*12974Ssam 	for (dr = dayrules; dr->dst_type >= 0; dr++)
126*12974Ssam 		if (dr->dst_type == zone.tz_dsttime)
127*12974Ssam 			break;
128*12974Ssam 	if (dr->dst_type >= 0) {
129*12974Ssam 		year = ct->tm_year + 1900;
130*12974Ssam 		for (ds = dr->dst_rules; ds->dayyr; ds++)
131*12974Ssam 			if (ds->dayyr == year)
132*12974Ssam 				break;
133*12974Ssam 		dalybeg = ds->daylb;	/* first Sun after dst starts */
134*12974Ssam 		daylend = ds->dayle;	/* first Sun after dst ends */
135*12974Ssam 		dalybeg = sunday(ct, dalybeg);
136*12974Ssam 		daylend = sunday(ct, daylend);
137*12974Ssam 		switch (dr->dst_hemi) {
138*12974Ssam 		case NTH:
139*12974Ssam 		    if (!(
140*12974Ssam 		       (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) &&
141*12974Ssam 		       (dayno<daylend || (dayno==daylend && ct->tm_hour<1))
142*12974Ssam 		    ))
143*12974Ssam 			    return(ct);
144*12974Ssam 		    break;
145*12974Ssam 		case STH:
146*12974Ssam 		    if (!(
147*12974Ssam 		       (dayno>dalybeg || (dayno==dalybeg && ct->tm_hour>=2)) ||
148*12974Ssam 		       (dayno<daylend || (dayno==daylend && ct->tm_hour<2))
149*12974Ssam 		    ))
150*12974Ssam 			    return(ct);
151*12974Ssam 		    break;
152*12974Ssam 		default:
153*12974Ssam 		    return(ct);
154*12974Ssam 		}
155*12974Ssam 	        copyt += dr->dst_hrs*60*60;
1561959Swnj 		ct = gmtime(&copyt);
1571959Swnj 		ct->tm_isdst++;
1581959Swnj 	}
1591959Swnj 	return(ct);
1601959Swnj }
1611959Swnj 
1621959Swnj /*
1631959Swnj  * The argument is a 0-origin day number.
1641959Swnj  * The value is the day number of the first
1651959Swnj  * Sunday on or after the day.
1661959Swnj  */
1671959Swnj static
1681959Swnj sunday(t, d)
1691959Swnj register struct tm *t;
1701959Swnj register int d;
1711959Swnj {
1721959Swnj 	if (d >= 58)
1731959Swnj 		d += dysize(t->tm_year) - 365;
1741959Swnj 	return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
1751959Swnj }
1761959Swnj 
1771959Swnj struct tm *
1781959Swnj gmtime(tim)
179*12974Ssam unsigned long *tim;
1801959Swnj {
1811959Swnj 	register int d0, d1;
182*12974Ssam 	unsigned long hms, day;
1831959Swnj 	register int *tp;
1841959Swnj 	static struct tm xtime;
1851959Swnj 
1861959Swnj 	/*
1871959Swnj 	 * break initial number into days
1881959Swnj 	 */
1891959Swnj 	hms = *tim % 86400;
1901959Swnj 	day = *tim / 86400;
1911959Swnj 	if (hms<0) {
1921959Swnj 		hms += 86400;
1931959Swnj 		day -= 1;
1941959Swnj 	}
1951959Swnj 	tp = (int *)&xtime;
1961959Swnj 
1971959Swnj 	/*
1981959Swnj 	 * generate hours:minutes:seconds
1991959Swnj 	 */
2001959Swnj 	*tp++ = hms%60;
2011959Swnj 	d1 = hms/60;
2021959Swnj 	*tp++ = d1%60;
2031959Swnj 	d1 /= 60;
2041959Swnj 	*tp++ = d1;
2051959Swnj 
2061959Swnj 	/*
2071959Swnj 	 * day is the day number.
2081959Swnj 	 * generate day of the week.
2091959Swnj 	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
2101959Swnj 	 */
2111959Swnj 
2121959Swnj 	xtime.tm_wday = (day+7340036)%7;
2131959Swnj 
2141959Swnj 	/*
2151959Swnj 	 * year number
2161959Swnj 	 */
2171959Swnj 	if (day>=0) for(d1=70; day >= dysize(d1); d1++)
2181959Swnj 		day -= dysize(d1);
2191959Swnj 	else for (d1=70; day<0; d1--)
2201959Swnj 		day += dysize(d1-1);
2211959Swnj 	xtime.tm_year = d1;
2221959Swnj 	xtime.tm_yday = d0 = day;
2231959Swnj 
2241959Swnj 	/*
2251959Swnj 	 * generate month
2261959Swnj 	 */
2271959Swnj 
2281959Swnj 	if (dysize(d1)==366)
2291959Swnj 		dmsize[1] = 29;
2301959Swnj 	for(d1=0; d0 >= dmsize[d1]; d1++)
2311959Swnj 		d0 -= dmsize[d1];
2321959Swnj 	dmsize[1] = 28;
2331959Swnj 	*tp++ = d0+1;
2341959Swnj 	*tp++ = d1;
2351959Swnj 	xtime.tm_isdst = 0;
2361959Swnj 	return(&xtime);
2371959Swnj }
2381959Swnj 
2391959Swnj char *
2401959Swnj asctime(t)
2411959Swnj struct tm *t;
2421959Swnj {
2431959Swnj 	register char *cp, *ncp;
2441959Swnj 	register int *tp;
2451959Swnj 
2461959Swnj 	cp = cbuf;
2471959Swnj 	for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;);
2481959Swnj 	ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday];
2491959Swnj 	cp = cbuf;
2501959Swnj 	*cp++ = *ncp++;
2511959Swnj 	*cp++ = *ncp++;
2521959Swnj 	*cp++ = *ncp++;
2531959Swnj 	cp++;
2541959Swnj 	tp = &t->tm_mon;
2551959Swnj 	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3];
2561959Swnj 	*cp++ = *ncp++;
2571959Swnj 	*cp++ = *ncp++;
2581959Swnj 	*cp++ = *ncp++;
2591959Swnj 	cp = ct_numb(cp, *--tp);
2601959Swnj 	cp = ct_numb(cp, *--tp+100);
2611959Swnj 	cp = ct_numb(cp, *--tp+100);
2621959Swnj 	cp = ct_numb(cp, *--tp+100);
2631959Swnj 	if (t->tm_year>=100) {
2641959Swnj 		cp[1] = '2';
265*12974Ssam 		cp[2] = '0' + t->tm_year >= 200;
2661959Swnj 	}
2671959Swnj 	cp += 2;
2681959Swnj 	cp = ct_numb(cp, t->tm_year+100);
2691959Swnj 	return(cbuf);
2701959Swnj }
2711959Swnj 
2721959Swnj dysize(y)
2731959Swnj {
2741959Swnj 	if((y%4) == 0)
2751959Swnj 		return(366);
2761959Swnj 	return(365);
2771959Swnj }
2781959Swnj 
2791959Swnj static char *
2801959Swnj ct_numb(cp, n)
2811959Swnj register char *cp;
2821959Swnj {
2831959Swnj 	cp++;
2841959Swnj 	if (n>=10)
2851959Swnj 		*cp++ = (n/10)%10 + '0';
2861959Swnj 	else
2871959Swnj 		*cp++ = ' ';
2881959Swnj 	*cp++ = n%10 + '0';
2891959Swnj 	return(cp);
2901959Swnj }
291