Ultrix-3.1/src/libc/gen/ctime.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * SCCSID: @(#)ctime.c	3.2	8/7/87
 */
/*
 * This routine converts time as follows.
 * The epoch is 0000 Jan 1 1970 GMT.
 * The argument time is in seconds since then.
 * The localtime(t) entry returns a pointer to an array
 * containing
 *  seconds (0-59)
 *  minutes (0-59)
 *  hours (0-23)
 *  day of month (1-31)
 *  month (0-11)
 *  year-1970
 *  weekday (0-6, Sun is 0)
 *  day of the year
 *  daylight savings flag
 *
 * The routine calls the system to determine the local
 * timezone and whether Daylight Saving Time is permitted locally.
 * (DST is then determined by the current US standard rules)
 * There is a table that accounts for the peculiarities
 * undergone by daylight time in 1974-1975.
 *
 * The routine does not work
 * in Saudi Arabia which runs on Solar time.
 *
 * asctime(tvec))
 * where tvec is produced by localtime
 * returns a ptr to a character string
 * that has the ascii time in the form
 *	Thu Jan 01 00:00:00 1970n0\\
 *	01234567890123456789012345
 *	0	  1	    2
 *
 * ctime(t) just calls localtime, then asctime.
 */

#include <sys/types.h>
#include <sys/timeb.h> 
#include <sys/time.h>

static	char	cbuf[26];
static	int	dmsize[12] =
{
	31,
	28,
	31,
	30,
	31,
	30,
	31,
	31,
	30,
	31,
	30,
	31
};

/*
 * The following table is used for 1974 and 1975 and
 * gives the day number of the first day after the Sunday of the
 * change.  Please note that these are 0 origin days.
 */
struct dstab {
	int	dayyr;
	int	daylb;
	int	dayle;
};

static struct dstab usdaytab[] = {
	1974,	5,	333,	/* 1974: Jan 6 - last Sun. in Nov */
	1975,	58,	303,	/* 1975: Last Sun. in Feb - last Sun in Oct */
	1976,	119,	303,	/* 1976: end Apr - end Oct */
	1977,	119,	303,	/* 1977: end Apr - end Oct */
	1978,	119,	303,	/* 1978: end Apr - end Oct */
	1979,	119,	303,	/* 1979: end Apr - end Oct */
	1980,	119,	303,	/* 1980: end Apr - end Oct */
	1981,	119,	303,	/* 1981: end Apr - end Oct */
	1982,	119,	303,	/* 1982: end Apr - end Oct */
	1983,	119,	303,	/* 1983: end Apr - end Oct */
	1984,	119,	303,	/* 1984: end Apr - end Oct */
	1985,	119,	303,	/* 1985: end Apr - end Oct */
	1986,	119,	303,	/* 1986: end Apr - end Oct */
	0,	96,	303,	/* all other years: beg Apr - end Oct */
};
static struct dstab ausdaytab[] = {
	1970,	400,	0,	/* 1970: no daylight saving at all */
	1971,	303,	0,	/* 1971: daylight saving from Oct 31 */
	1972,	303,	58,	/* 1972: Jan 1 -> Feb 27 & Oct 31 -> dec 31 */
	0,	303,	65,	/* others: -> Mar 7, Oct 31 -> */
};

/*
 * The European tables ... based on hearsay
 * Believed correct for:
 *	WE:	Great Britain, Ireland, Portugal
 *	ME:	Belgium, Luxembourg, Netherlands, Denmark, Norway,
 *		Austria, Poland, Czechoslovakia, Sweden, Switzerland,
 *		DDR, DBR, France, Spain, Hungary, Italy, Jugoslavia
 * Eastern European dst is unknown, we'll make it ME until someone speaks up.
 *	EE:	Bulgaria, Finland, Greece, Rumania, Turkey, Western Russia
 */
static struct dstab wedaytab[] = {
	1983,	86,	303,	/* 1983: end March - end Oct */
	1984,	86,	303,	/* 1984: end March - end Oct */
	1985,	86,	303,	/* 1985: end March - end Oct */
	0,	86,	303,	/* others: end March - end Oct */
};

static struct dstab medaytab[] = {
	1983,	86,	272,	/* 1983: end March - end Sep */
	1984,	86,	272,	/* 1984: end March - end Sep */
	1985,	86,	272,	/* 1985: end March - end Sep */
	0,	86,	272,	/* others: saving end March - end Sep */
};

static struct dayrules {
	int		dst_type;	/* number obtained from system */
	int		dst_hrs;	/* hours to add when dst on */
	struct	dstab *	dst_rules;	/* one of the above */
	enum {STH,NTH}	dst_hemi;	/* southern, northern hemisphere */
} dayrules [] = {
	DST_USA,	1,	usdaytab,	NTH,
	DST_AUST,	1,	ausdaytab,	STH,
	DST_WET,	1,	wedaytab,	NTH,
	DST_MET,	1,	medaytab,	NTH,
	DST_EET,	1,	medaytab,	NTH,	/* XXX */
	-1,
};

#define NULL_DAYRULES ((struct dayrules *)0)
struct tm	*gmtime();
char		*ct_numb();
struct tm	*localtime();
char	*ctime();
char	*ct_num();
char	*asctime();

dysize(y)
{
	if((y%4) == 0)
		return(366);
	return(365);
}


char *
ctime(t)
long *t;
{
	return(asctime(localtime(t)));
}

struct tm *
localtime(gmt_value)
	time_t *gmt_value;		/* Greenwich Mean Time value */
{
	register struct tm *ct;
	register struct dayrules *dr;
	time_t local_time;

	/* We assume that the timezone will not change across calls to
	 * this routine, so the seconds west of Greenwich and the daylight
	 * savings time rules for the time zone can be saved across calls.
	 */
	static time_t seconds_west;
	static struct dayrules *saved_dr = NULL_DAYRULES;

	/* Get the pointer to the saved daylight savings time rules.  If it
	 * is NULL then this is the first time through then we have to set up 
	 * the static information about this timezone.
	 */
	dr = saved_dr;
	if (dr == NULL_DAYRULES){
		struct timeb systime;

		/* Get the time zone information.  Not interested in the
		 * timeofday.
		 */
		ftime(&systime);
		
		/* Calculate the seconds west of Greewich Mean Time for
		 * this time zone.
		 */
		seconds_west =  (long)systime.timezone*60;

		/* Get the pointer to the daylight savings rules for the
		 * time zone, and save the pointer for the next call.
		 */
		dr = dayrules ; 
		while (dr->dst_type >= 0 && dr->dst_type != systime.dstflag)
			dr++;
		saved_dr = dr;
	}

	local_time = *gmt_value - seconds_west;
	ct = gmtime(&local_time);

	if (dr->dst_type >= 0) {
	
		register int dayno = ct->tm_yday;
		register daylbeg, daylend;
		register struct dstab *ds = dr->dst_rules;
		int year = ct->tm_year + 1900;

		while (ds->dayyr && ds->dayyr != year)
			ds++;

		/* Calculate first Sunday after DST begins and first
		 * Sunday after it ends.
		 */
		daylbeg = sunday(ct,ds->daylb);
		daylend = sunday(ct,ds->dayle);

		switch (dr->dst_hemi) {
		case NTH:
		    if (!(
		       (dayno>daylbeg || (dayno==daylbeg && ct->tm_hour>=2)) &&
		       (dayno<daylend || (dayno==daylend && ct->tm_hour<1))
		    ))
			    return(ct);
		    break;
		case STH:
		    if (!(
		       (dayno>daylbeg || (dayno==daylbeg && ct->tm_hour>=2)) ||
		       (dayno<daylend || (dayno==daylend && ct->tm_hour<2))
		    ))
			    return(ct);
		    break;
		default:
		    return(ct);
		}
	        local_time += dr->dst_hrs*60*60;
		ct = gmtime(&local_time);
		ct->tm_isdst++;
	}
	return(ct);
}

/*
 * The argument is a 0-origin day number.
 * The value is the day number of the first
 * Sunday on or after the day.
 */
static
sunday(t, d)
register struct tm *t;
register int d;
{
	if (d >= 58)
		d += dysize(t->tm_year) - 365;
	return(d - (d - t->tm_yday + t->tm_wday + 700) % 7);
}

struct tm *
gmtime(tim)
long *tim;
{
	register int d0, d1;
	long hms, day;
	register int *tp;
	static struct tm xtime;

	/*
	 * break initial number into days
	 */
	hms = *tim % 86400;
	day = *tim / 86400;
	if (hms<0) {
		hms += 86400;
		day -= 1;
	}
	tp = (int *)&xtime;

	/*
	 * generate hours:minutes:seconds
	 */
	*tp++ = hms%60;
	d1 = hms/60;
	*tp++ = d1%60;
	d1 /= 60;
	*tp++ = d1;

	/*
	 * day is the day number.
	 * generate day of the week.
	 * The addend is 4 mod 7 (1/1/1970 was Thursday)
	 */

	xtime.tm_wday = (day+7340036)%7;

	/*
	 * year number
	 */
	if (day>=0) for(d1=70; day >= dysize(d1); d1++)
		day -= dysize(d1);
	else for (d1=70; day<0; d1--)
		day += dysize(d1-1);
	xtime.tm_year = d1;
	xtime.tm_yday = d0 = day;

	/*
	 * generate month
	 */

	if (dysize(d1)==366)
		dmsize[1] = 29;
	for(d1=0; d0 >= dmsize[d1]; d1++)
		d0 -= dmsize[d1];
	dmsize[1] = 28;
	*tp++ = d0+1;
	*tp++ = d1;
	xtime.tm_isdst = 0;
	return(&xtime);
}

char *
asctime(t)
struct tm *t;
{
	register char *cp, *ncp;
	register int *tp;

	cp = cbuf;
	for (ncp = "Day Mon 00 00:00:00 1900\n"; *cp++ = *ncp++;);
	ncp = &"SunMonTueWedThuFriSat"[3*t->tm_wday];
	cp = cbuf;
	*cp++ = *ncp++;
	*cp++ = *ncp++;
	*cp++ = *ncp++;
	cp++;
	tp = &t->tm_mon;
	ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[(*tp)*3];
	*cp++ = *ncp++;
	*cp++ = *ncp++;
	*cp++ = *ncp++;
	cp = ct_numb(cp, *--tp);
	cp = ct_numb(cp, *--tp+100);
	cp = ct_numb(cp, *--tp+100);
	cp = ct_numb(cp, *--tp+100);
	if (t->tm_year>=100) {
		cp++;
		*cp++ = '2';
		if (t->tm_year >= 200) {
			*cp = '1';
			t->tm_year -= 200;
		} else {
			*cp = '0';
			t->tm_year -= 100;
		}
	} else {
		cp += 2;
	}
	cp = ct_numb(cp, t->tm_year+100);
	return(cbuf);
}

static char *
ct_numb(cp, n)
register char *cp;
{
	cp++;
	if (n>=10)
		*cp++ = (n/10)%10 + '0';
	else
		*cp++ = ' ';
	*cp++ = n%10 + '0';
	return(cp);
}