#include "all.h"
static int sunday(Tm *t, int d);
static int dysize(int);
static void ct_numb(char*, int);
static void klocaltime(long tim, Tm *ct);
static void kgmtime(long tim, Tm *ct);
static char 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.
*/
static struct
{
short yrfrom;
short yrto;
short daylb;
short dayle;
} daytab[] =
{
87, 999, 97, 303,
76, 86, 119, 303,
75, 75, 58, 303,
74, 74, 5, 333,
0, 73, 119, 303,
};
static struct
{
short minuteswest; /* minutes west of Greenwich */
short dsttime; /* dst correction */
} timezone =
{
5*60, 1
};
static void
klocaltime(long tim, Tm *ct)
{
int daylbegin, daylend, dayno, i;
long copyt;
copyt = tim - timezone.minuteswest*60L;
kgmtime(copyt, ct);
dayno = ct->yday;
for(i=0;; i++)
if(ct->year >= daytab[i].yrfrom &&
ct->year <= daytab[i].yrto) {
daylbegin = sunday(ct, daytab[i].daylb);
daylend = sunday(ct, daytab[i].dayle);
break;
}
if(timezone.dsttime &&
(dayno>daylbegin || (dayno==daylbegin && ct->hour>=2)) &&
(dayno<daylend || (dayno==daylend && ct->hour<1))) {
copyt += 60L*60L;
kgmtime(copyt, ct);
}
}
/*
* The argument is a 0-origin day number.
* The value is the day number of the last
* Sunday before or after the day.
*/
static
sunday(Tm *t, int d)
{
if(d >= 58)
d += dysize(t->year) - 365;
return d - (d - t->yday + t->wday + 700) % 7;
}
static void
kgmtime(long tim, Tm *ct)
{
int d0, d1;
long hms, day;
/*
* break initial number into days
*/
hms = tim % 86400L;
day = 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 = 70; day >= dysize(d1); d1++)
day -= dysize(d1);
else
for (d1 = 70; day < 0; d1--)
day += dysize(d1-1);
ct->year = d1;
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;
}
void
datestr(char *s, long t)
{
Tm tm;
klocaltime(t, &tm);
sprint(s, "%.4d%.2d%.2d", tm.year+1900, tm.mon+1, tm.mday);
}
int
Tfmt(Fmt *f1)
{
char s[30];
char *cp;
long t;
Tm tm;
t = va_arg(f1->args, long);
if(t == 0)
return fmtstrcpy(f1, "The Epoch");
klocaltime(t, &tm);
strcpy(s, "Day Mon 00 00:00:00 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);
if(tm.year >= 100) {
s[20] = '2';
s[21] = '0';
}
ct_numb(s+22, tm.year+100);
return fmtstrcpy(f1, 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
*/
long
nextime(long t, int hr, int day)
{
Tm tm;
int nhr;
if(hr < 0 || hr >= 24)
hr = 5;
if((day&0x7f) == 0x7f)
day = 0;
loop:
klocaltime(t, &tm);
t -= tm.sec;
t -= tm.min*60;
nhr = tm.hour;
do {
t += 60*60;
nhr++;
} while(nhr%24 != hr);
klocaltime(t, &tm);
if(tm.hour != hr) {
t += 60*60;
klocaltime(t, &tm);
if(tm.hour != hr) {
t -= 60*60;
klocaltime(t, &tm);
}
}
if(day & (1<<tm.wday)) {
t += 12*60*60;
goto loop;
}
return t;
}
|