Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/fs/port/time.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include	"all.h"
#include	"mem.h"

typedef struct Toy Toy;
struct Toy {
	Lock;
	Timet	base;
	ulong	basetk;
};

static Toy toy;

enum {
	T	= 500000000,		/* needs to be 0 mod HZ */
};

Timet
toytime(void)
{
	ulong u, t;

	ilock(&toy);
	t = Ticks;
	if(toy.base == 0){
		toy.base = mktime;
		toy.basetk = t;
	}
	u = t - toy.basetk;
	while(u >= T){
		toy.basetk += T;
		toy.base += TK2SEC(T);
		u -= T;
	}
	iunlock(&toy);

	return toy.base + TK2SEC(u);
}

#define SEC2MIN 60L
#define SEC2HOUR (60L*SEC2MIN)
#define SEC2DAY  (24L*SEC2HOUR)

/*
 *  days per month plus days/year
 */
int	rtdmsize[] =
{
	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int	rtldmsize[] =
{
	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

/*
 *  return the days/month for the given year
 */
int*
yrsize(int y)
{
	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
		return rtldmsize;
	else
		return rtdmsize;
}

void
sec2rtc(Timet secs, Rtc *rtc)
{
	int d, *d2m;
	Timet hms, day;

	/*
	 * break initial number into days
	 */
	hms = (uvlong)secs % SEC2DAY;
	day = (uvlong)secs / SEC2DAY;
	if(hms < 0) {
		hms += SEC2DAY;
		day -= 1;
	}

	/*
	 * generate hours:minutes:seconds
	 */
	rtc->sec = hms % 60;
	d = hms / 60;
	rtc->min = d % 60;
	d /= 60;
	rtc->hour = d;

	/*
	 * year number
	 */
	if(day >= 0)
		for(d = 1970; day >= *yrsize(d); d++)
			day -= *yrsize(d);
	else
		for(d = 1970; day < 0; d--)
			day += *yrsize(d-1);
	rtc->year = d;

	/*
	 * generate month
	 */
	d2m = yrsize(rtc->year);
	for(d = 1; day >= d2m[d]; d++)
		day -= d2m[d];
	rtc->mday = day + 1;
	rtc->mon = d;
}

Timet
rtc2sec(Rtc *rtc)
{
	Timet secs;
	int i, *d2m;

	secs = 0;

	/*
	 *  seconds per year
	 */
	for(i = 1970; i < rtc->year; i++) {
		d2m = yrsize(i);
		secs += d2m[0] * SEC2DAY;
	}

	/*
	 *  seconds per month
	 */
	d2m = yrsize(rtc->year);
	for(i = 1; i < rtc->mon; i++)
		secs += d2m[i] * SEC2DAY;

	secs += (rtc->mday-1) * SEC2DAY;
	secs += rtc->hour * SEC2HOUR;
	secs += rtc->min * SEC2MIN;
	secs += rtc->sec;

	return secs;
}

Timet
time(void)
{
	Timet t, dt;

	t = toytime();
	while(tim.bias != 0) {			/* adjust at rate 1 sec/min */
		dt = t - tim.lasttoy;
		if(dt < MINUTE(1))
			break;
		if(tim.bias >= 0) {
			tim.bias -= SECOND(1);
			tim.offset += SECOND(1);
		} else {
			tim.bias += SECOND(1);
			tim.offset -= SECOND(1);
		}
		tim.lasttoy += MINUTE(1);
	}
	return t + tim.offset;
}

void
settime(Timet nt)
{
	Timet dt;

	dt = nt - time();
	tim.lasttoy = toytime();
	if(dt > MAXBIAS || dt < -MAXBIAS) {	/* too much, just set it */
		tim.bias = 0;
		tim.offset = nt - tim.lasttoy;
	} else
		tim.bias = dt;
}

void
prdate(void)
{
	Timet t;

	t = time();
	if(tim.bias >= 0)
		print("%T + %ld\n", t, tim.bias);
	else
		print("%T - %ld\n", t, -tim.bias);
}

static	int	dysize(int);
static	void	ct_numb(char*, int);
void		localtime(Timet, Tm*);
void		gmtime(Timet, Tm*);

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

/*
 * since we are the fileserver and can't depend on files being where
 * they belong, we keep the equivalent of /adm/timezone/local in 
 * the following structure, which is compiled into the executable.
 */
typedef struct{
	char	stname[4];
	char	dlname[4];
	long	stdiff;
	long	dldiff;
	long	dlpairs[150];
} Timezone;

#include "timezone.h"

void
localtime(Timet tim, Tm *ct)
{
	long t, *p;
	int dlflag;

	t = tim + timezone.stdiff;
	dlflag = 0;
	for(p = timezone.dlpairs; *p; p += 2)
		if(t >= p[0])
		if(t < p[1]) {
			t = tim + timezone.dldiff;
			dlflag++;
			break;
		}
	gmtime(t, ct);
	if(dlflag){
		strcpy(ct->zone, timezone.dlname);
		ct->tzoff = timezone.dldiff;
	} else {
		strcpy(ct->zone, timezone.stname);
		ct->tzoff = timezone.stdiff;
	}
}

void
gmtime(Timet tim, Tm *ct)
{
	int d0, d1;
	Timet hms, day;

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

	/*
	 * generate hours:minutes:seconds
	 */
	ct->sec = hms % 60;
	d1 = hms / 60;
	ct->min = d1 % 60;
	d1 /= 60;
	ct->hour = d1;

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

	ct->wday = (day + 7340036L) % 7;

	/*
	 * year number
	 */
	if(day >= 0)
		for(d1 = 1970; day >= dysize(d1); d1++)
			day -= dysize(d1);
	else
		for(d1 = 1970; day < 0; d1--)
			day += dysize(d1-1);
	ct->year = d1-1900;
	ct->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;
	ct->mday = d0 + 1;
	ct->mon = d1;
	ct->tzoff = 0;
	strcpy(ct->zone, "GMT");
}

void
datestr(char *s, Timet t)
{
	Tm tm;

	localtime(t, &tm);
	sprint(s, "%.4d%.2d%.2d", tm.year+1900, tm.mon+1, tm.mday);
}

int
Tfmt(Fmt* fmt)
{
	char s[30];
	char *cp;
	Timet t;
	Tm tm;

	t = va_arg(fmt->args, Timet);
	if(t == 0)
		return fmtstrcpy(fmt, "The Epoch");

	localtime(t, &tm);
	strcpy(s, "Day Mon 00 00:00:00 GMT 1900");
	cp = &"SunMonTueWedThuFriSat"[tm.wday*3];
	s[0] = cp[0];
	s[1] = cp[1];
	s[2] = cp[2];
	cp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[tm.mon*3];
	s[4] = cp[0];
	s[5] = cp[1];
	s[6] = cp[2];
	ct_numb(s+8, tm.mday);
	ct_numb(s+11, tm.hour+100);
	ct_numb(s+14, tm.min+100);
	ct_numb(s+17, tm.sec+100);
	cp = tm.zone;
	s[20] = *cp++;
	s[21] = *cp++;
	s[22] = *cp;
	if(tm.year >= 100) {
		s[24] = '2';
		s[25] = '0';
	}
	ct_numb(s+26, tm.year+100);

	return fmtstrcpy(fmt, s);
}

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

static
void
ct_numb(char *cp, int n)
{
	if(n >= 10)
		cp[0] = (n/10)%10 + '0';
	else
		cp[0] = ' ';
	cp[1] = n%10 + '0';
}

/*
 * compute the next time after t
 * that has hour hr and is not on
 * day in bitpattern --
 * for automatic dumps
 */
Timet
nextime(Timet t, int hr, int day)
{
	int nhr;
	Tm tm;

	if(hr < 0 || hr >= 24)
		hr = 5;
	if((day&0x7f) == 0x7f)
		day = 0;
	for (;;) {
		localtime(t, &tm);
		t -= tm.sec;
		t -= tm.min*60;
		nhr = tm.hour;
		do {
			t += 60*60;
			nhr++;
		} while(nhr%24 != hr);
		localtime(t, &tm);
		if(tm.hour != hr) {
			t += 60*60;
			localtime(t, &tm);
			if(tm.hour != hr) {
				t -= 60*60;
				localtime(t, &tm);
			}
		}
		if(day & (1<<tm.wday))
			t += 12*60*60;
		else
			return t;
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.