xref: /csrg-svn/lib/libc/gen/ctime.c (revision 25662)
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(&copyt);
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(&copyt);
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