13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * This routine converts time as follows.
33e12c5d1SDavid du Colombier * The epoch is 0000 Jan 1 1970 GMT.
43e12c5d1SDavid du Colombier * The argument time is in seconds since then.
53e12c5d1SDavid du Colombier * The localtime(t) entry returns a pointer to an array
63e12c5d1SDavid du Colombier * containing
73e12c5d1SDavid du Colombier *
83e12c5d1SDavid du Colombier * seconds (0-59)
93e12c5d1SDavid du Colombier * minutes (0-59)
103e12c5d1SDavid du Colombier * hours (0-23)
113e12c5d1SDavid du Colombier * day of month (1-31)
123e12c5d1SDavid du Colombier * month (0-11)
133e12c5d1SDavid du Colombier * year-1970
143e12c5d1SDavid du Colombier * weekday (0-6, Sun is 0)
153e12c5d1SDavid du Colombier * day of the year
163e12c5d1SDavid du Colombier * daylight savings flag
173e12c5d1SDavid du Colombier *
183e12c5d1SDavid du Colombier * The routine gets the daylight savings time from the environment.
193e12c5d1SDavid du Colombier *
203e12c5d1SDavid du Colombier * asctime(tvec))
213e12c5d1SDavid du Colombier * where tvec is produced by localtime
223e12c5d1SDavid du Colombier * returns a ptr to a character string
233e12c5d1SDavid du Colombier * that has the ascii time in the form
243e12c5d1SDavid du Colombier *
253e12c5d1SDavid du Colombier * \\
263e12c5d1SDavid du Colombier * Thu Jan 01 00:00:00 GMT 1970n0
273e12c5d1SDavid du Colombier * 012345678901234567890123456789
283e12c5d1SDavid du Colombier * 0 1 2
293e12c5d1SDavid du Colombier *
303e12c5d1SDavid du Colombier * ctime(t) just calls localtime, then asctime.
313e12c5d1SDavid du Colombier */
323e12c5d1SDavid du Colombier
333e12c5d1SDavid du Colombier #include <u.h>
343e12c5d1SDavid du Colombier #include <libc.h>
353e12c5d1SDavid du Colombier
363e12c5d1SDavid du Colombier static char dmsize[12] =
373e12c5d1SDavid du Colombier {
383e12c5d1SDavid du Colombier 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier
413e12c5d1SDavid du Colombier /*
423e12c5d1SDavid du Colombier * The following table is used for 1974 and 1975 and
433e12c5d1SDavid du Colombier * gives the day number of the first day after the Sunday of the
443e12c5d1SDavid du Colombier * change.
453e12c5d1SDavid du Colombier */
463e12c5d1SDavid du Colombier
473e12c5d1SDavid du Colombier static int dysize(int);
483e12c5d1SDavid du Colombier static void ct_numb(char*, int);
493e12c5d1SDavid du Colombier
50*54dec067SDavid du Colombier #define TZSIZE ((136*2)+10) /* 1970-2106; match tm2sec.c */
51*54dec067SDavid du Colombier
523e12c5d1SDavid du Colombier static void readtimezone(void);
533e12c5d1SDavid du Colombier static int rd_name(char**, char*);
543e12c5d1SDavid du Colombier static int rd_long(char**, long*);
553e12c5d1SDavid du Colombier static
563e12c5d1SDavid du Colombier struct
573e12c5d1SDavid du Colombier {
583e12c5d1SDavid du Colombier char stname[4];
593e12c5d1SDavid du Colombier char dlname[4];
603e12c5d1SDavid du Colombier long stdiff;
613e12c5d1SDavid du Colombier long dldiff;
62*54dec067SDavid du Colombier ulong dlpairs[TZSIZE];
633e12c5d1SDavid du Colombier } timezone;
643e12c5d1SDavid du Colombier
653e12c5d1SDavid du Colombier char*
ctime(long t)663e12c5d1SDavid du Colombier ctime(long t)
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier return asctime(localtime(t));
693e12c5d1SDavid du Colombier }
703e12c5d1SDavid du Colombier
713e12c5d1SDavid du Colombier Tm*
localtime(long atim)72*54dec067SDavid du Colombier localtime(long atim) /* should be ulong, but it's too late */
733e12c5d1SDavid du Colombier {
743e12c5d1SDavid du Colombier Tm *ct;
75*54dec067SDavid du Colombier ulong tim, t, *p;
763e12c5d1SDavid du Colombier int dlflag;
773e12c5d1SDavid du Colombier
78*54dec067SDavid du Colombier tim = atim;
793e12c5d1SDavid du Colombier if(timezone.stname[0] == 0)
803e12c5d1SDavid du Colombier readtimezone();
813e12c5d1SDavid du Colombier t = tim + timezone.stdiff;
823e12c5d1SDavid du Colombier dlflag = 0;
833e12c5d1SDavid du Colombier for(p = timezone.dlpairs; *p; p += 2)
843e12c5d1SDavid du Colombier if(t >= p[0])
853e12c5d1SDavid du Colombier if(t < p[1]) {
863e12c5d1SDavid du Colombier t = tim + timezone.dldiff;
873e12c5d1SDavid du Colombier dlflag++;
883e12c5d1SDavid du Colombier break;
893e12c5d1SDavid du Colombier }
903e12c5d1SDavid du Colombier ct = gmtime(t);
917dd7cddfSDavid du Colombier if(dlflag){
927dd7cddfSDavid du Colombier strcpy(ct->zone, timezone.dlname);
937dd7cddfSDavid du Colombier ct->tzoff = timezone.dldiff;
947dd7cddfSDavid du Colombier } else {
957dd7cddfSDavid du Colombier strcpy(ct->zone, timezone.stname);
967dd7cddfSDavid du Colombier ct->tzoff = timezone.stdiff;
977dd7cddfSDavid du Colombier }
983e12c5d1SDavid du Colombier return ct;
993e12c5d1SDavid du Colombier }
1003e12c5d1SDavid du Colombier
1013e12c5d1SDavid du Colombier Tm*
gmtime(long atim)102*54dec067SDavid du Colombier gmtime(long atim) /* should be ulong, but it's too late */
1033e12c5d1SDavid du Colombier {
1043e12c5d1SDavid du Colombier int d0, d1;
1053e12c5d1SDavid du Colombier long hms, day;
106*54dec067SDavid du Colombier ulong tim;
1073e12c5d1SDavid du Colombier static Tm xtime;
1083e12c5d1SDavid du Colombier
1093e12c5d1SDavid du Colombier /*
1103e12c5d1SDavid du Colombier * break initial number into days
1113e12c5d1SDavid du Colombier */
112*54dec067SDavid du Colombier tim = atim;
113*54dec067SDavid du Colombier hms = tim % 86400L;
114*54dec067SDavid du Colombier day = tim / 86400L;
1153e12c5d1SDavid du Colombier if(hms < 0) {
1163e12c5d1SDavid du Colombier hms += 86400L;
1173e12c5d1SDavid du Colombier day -= 1;
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier
1203e12c5d1SDavid du Colombier /*
1213e12c5d1SDavid du Colombier * generate hours:minutes:seconds
1223e12c5d1SDavid du Colombier */
1233e12c5d1SDavid du Colombier xtime.sec = hms % 60;
1243e12c5d1SDavid du Colombier d1 = hms / 60;
1253e12c5d1SDavid du Colombier xtime.min = d1 % 60;
1263e12c5d1SDavid du Colombier d1 /= 60;
1273e12c5d1SDavid du Colombier xtime.hour = d1;
1283e12c5d1SDavid du Colombier
1293e12c5d1SDavid du Colombier /*
1303e12c5d1SDavid du Colombier * day is the day number.
1313e12c5d1SDavid du Colombier * generate day of the week.
1323e12c5d1SDavid du Colombier * The addend is 4 mod 7 (1/1/1970 was Thursday)
1333e12c5d1SDavid du Colombier */
1343e12c5d1SDavid du Colombier
1353e12c5d1SDavid du Colombier xtime.wday = (day + 7340036L) % 7;
1363e12c5d1SDavid du Colombier
1373e12c5d1SDavid du Colombier /*
1383e12c5d1SDavid du Colombier * year number
1393e12c5d1SDavid du Colombier */
1403e12c5d1SDavid du Colombier if(day >= 0)
1417dd7cddfSDavid du Colombier for(d1 = 1970; day >= dysize(d1); d1++)
1423e12c5d1SDavid du Colombier day -= dysize(d1);
1433e12c5d1SDavid du Colombier else
1447dd7cddfSDavid du Colombier for (d1 = 1970; day < 0; d1--)
1453e12c5d1SDavid du Colombier day += dysize(d1-1);
1467dd7cddfSDavid du Colombier xtime.year = d1-1900;
1473e12c5d1SDavid du Colombier xtime.yday = d0 = day;
1483e12c5d1SDavid du Colombier
1493e12c5d1SDavid du Colombier /*
1503e12c5d1SDavid du Colombier * generate month
1513e12c5d1SDavid du Colombier */
1523e12c5d1SDavid du Colombier
1533e12c5d1SDavid du Colombier if(dysize(d1) == 366)
1543e12c5d1SDavid du Colombier dmsize[1] = 29;
1553e12c5d1SDavid du Colombier for(d1 = 0; d0 >= dmsize[d1]; d1++)
1563e12c5d1SDavid du Colombier d0 -= dmsize[d1];
1573e12c5d1SDavid du Colombier dmsize[1] = 28;
1583e12c5d1SDavid du Colombier xtime.mday = d0 + 1;
1593e12c5d1SDavid du Colombier xtime.mon = d1;
1603e12c5d1SDavid du Colombier strcpy(xtime.zone, "GMT");
1613e12c5d1SDavid du Colombier return &xtime;
1623e12c5d1SDavid du Colombier }
1633e12c5d1SDavid du Colombier
1643e12c5d1SDavid du Colombier char*
asctime(Tm * t)1653e12c5d1SDavid du Colombier asctime(Tm *t)
1663e12c5d1SDavid du Colombier {
1673e12c5d1SDavid du Colombier char *ncp;
1683e12c5d1SDavid du Colombier static char cbuf[30];
1693e12c5d1SDavid du Colombier
1703e12c5d1SDavid du Colombier strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
1713e12c5d1SDavid du Colombier ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
1723e12c5d1SDavid du Colombier cbuf[0] = *ncp++;
1733e12c5d1SDavid du Colombier cbuf[1] = *ncp++;
1743e12c5d1SDavid du Colombier cbuf[2] = *ncp;
1753e12c5d1SDavid du Colombier ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
1763e12c5d1SDavid du Colombier cbuf[4] = *ncp++;
1773e12c5d1SDavid du Colombier cbuf[5] = *ncp++;
1783e12c5d1SDavid du Colombier cbuf[6] = *ncp;
1793e12c5d1SDavid du Colombier ct_numb(cbuf+8, t->mday);
1803e12c5d1SDavid du Colombier ct_numb(cbuf+11, t->hour+100);
1813e12c5d1SDavid du Colombier ct_numb(cbuf+14, t->min+100);
1823e12c5d1SDavid du Colombier ct_numb(cbuf+17, t->sec+100);
1833e12c5d1SDavid du Colombier ncp = t->zone;
1843e12c5d1SDavid du Colombier cbuf[20] = *ncp++;
1853e12c5d1SDavid du Colombier cbuf[21] = *ncp++;
1863e12c5d1SDavid du Colombier cbuf[22] = *ncp;
1873e12c5d1SDavid du Colombier if(t->year >= 100) {
1883e12c5d1SDavid du Colombier cbuf[24] = '2';
189*54dec067SDavid du Colombier cbuf[25] = '0';
1903e12c5d1SDavid du Colombier }
1913e12c5d1SDavid du Colombier ct_numb(cbuf+26, t->year+100);
1923e12c5d1SDavid du Colombier return cbuf;
1933e12c5d1SDavid du Colombier }
1943e12c5d1SDavid du Colombier
1953e12c5d1SDavid du Colombier static
dysize(int y)1963e12c5d1SDavid du Colombier dysize(int y)
1973e12c5d1SDavid du Colombier {
1983e12c5d1SDavid du Colombier
1997dd7cddfSDavid du Colombier if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
2003e12c5d1SDavid du Colombier return 366;
2013e12c5d1SDavid du Colombier return 365;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier
2043e12c5d1SDavid du Colombier static
2053e12c5d1SDavid du Colombier void
ct_numb(char * cp,int n)2063e12c5d1SDavid du Colombier ct_numb(char *cp, int n)
2073e12c5d1SDavid du Colombier {
2083e12c5d1SDavid du Colombier
2093e12c5d1SDavid du Colombier cp[0] = ' ';
2103e12c5d1SDavid du Colombier if(n >= 10)
2113e12c5d1SDavid du Colombier cp[0] = (n/10)%10 + '0';
2123e12c5d1SDavid du Colombier cp[1] = n%10 + '0';
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier
2153e12c5d1SDavid du Colombier static
2163e12c5d1SDavid du Colombier void
readtimezone(void)2173e12c5d1SDavid du Colombier readtimezone(void)
2183e12c5d1SDavid du Colombier {
2193e12c5d1SDavid du Colombier char buf[TZSIZE*11+30], *p;
2203e12c5d1SDavid du Colombier int i;
2213e12c5d1SDavid du Colombier
2223e12c5d1SDavid du Colombier memset(buf, 0, sizeof(buf));
2233e12c5d1SDavid du Colombier i = open("/env/timezone", 0);
2243e12c5d1SDavid du Colombier if(i < 0)
2253e12c5d1SDavid du Colombier goto error;
2263b56890dSDavid du Colombier if(read(i, buf, sizeof(buf)) >= sizeof(buf)){
2273b56890dSDavid du Colombier close(i);
2283e12c5d1SDavid du Colombier goto error;
2293b56890dSDavid du Colombier }
2303e12c5d1SDavid du Colombier close(i);
2313e12c5d1SDavid du Colombier p = buf;
2323e12c5d1SDavid du Colombier if(rd_name(&p, timezone.stname))
2333e12c5d1SDavid du Colombier goto error;
2343e12c5d1SDavid du Colombier if(rd_long(&p, &timezone.stdiff))
2353e12c5d1SDavid du Colombier goto error;
2363e12c5d1SDavid du Colombier if(rd_name(&p, timezone.dlname))
2373e12c5d1SDavid du Colombier goto error;
2383e12c5d1SDavid du Colombier if(rd_long(&p, &timezone.dldiff))
2393e12c5d1SDavid du Colombier goto error;
2403e12c5d1SDavid du Colombier for(i=0; i<TZSIZE; i++) {
241*54dec067SDavid du Colombier if(rd_long(&p, (long *)&timezone.dlpairs[i]))
2423e12c5d1SDavid du Colombier goto error;
2433e12c5d1SDavid du Colombier if(timezone.dlpairs[i] == 0)
2443e12c5d1SDavid du Colombier return;
2453e12c5d1SDavid du Colombier }
246*54dec067SDavid du Colombier /* array too small for input */
2473e12c5d1SDavid du Colombier error:
2483e12c5d1SDavid du Colombier timezone.stdiff = 0;
2493e12c5d1SDavid du Colombier strcpy(timezone.stname, "GMT");
2503e12c5d1SDavid du Colombier timezone.dlpairs[0] = 0;
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier
2533e12c5d1SDavid du Colombier static
rd_name(char ** f,char * p)2543e12c5d1SDavid du Colombier rd_name(char **f, char *p)
2553e12c5d1SDavid du Colombier {
2563e12c5d1SDavid du Colombier int c, i;
2573e12c5d1SDavid du Colombier
2583e12c5d1SDavid du Colombier for(;;) {
2593e12c5d1SDavid du Colombier c = *(*f)++;
2603e12c5d1SDavid du Colombier if(c != ' ' && c != '\n')
2613e12c5d1SDavid du Colombier break;
2623e12c5d1SDavid du Colombier }
2633e12c5d1SDavid du Colombier for(i=0; i<3; i++) {
2643e12c5d1SDavid du Colombier if(c == ' ' || c == '\n')
2653e12c5d1SDavid du Colombier return 1;
2663e12c5d1SDavid du Colombier *p++ = c;
2673e12c5d1SDavid du Colombier c = *(*f)++;
2683e12c5d1SDavid du Colombier }
2693e12c5d1SDavid du Colombier if(c != ' ' && c != '\n')
2703e12c5d1SDavid du Colombier return 1;
2713e12c5d1SDavid du Colombier *p = 0;
2723e12c5d1SDavid du Colombier return 0;
2733e12c5d1SDavid du Colombier }
2743e12c5d1SDavid du Colombier
2753e12c5d1SDavid du Colombier static
rd_long(char ** f,long * p)2763e12c5d1SDavid du Colombier rd_long(char **f, long *p)
2773e12c5d1SDavid du Colombier {
2783e12c5d1SDavid du Colombier int c, s;
2793e12c5d1SDavid du Colombier long l;
2803e12c5d1SDavid du Colombier
2813e12c5d1SDavid du Colombier s = 0;
2823e12c5d1SDavid du Colombier for(;;) {
2833e12c5d1SDavid du Colombier c = *(*f)++;
2843e12c5d1SDavid du Colombier if(c == '-') {
2853e12c5d1SDavid du Colombier s++;
2863e12c5d1SDavid du Colombier continue;
2873e12c5d1SDavid du Colombier }
2883e12c5d1SDavid du Colombier if(c != ' ' && c != '\n')
2893e12c5d1SDavid du Colombier break;
2903e12c5d1SDavid du Colombier }
2913e12c5d1SDavid du Colombier if(c == 0) {
2923e12c5d1SDavid du Colombier *p = 0;
2933e12c5d1SDavid du Colombier return 0;
2943e12c5d1SDavid du Colombier }
2953e12c5d1SDavid du Colombier l = 0;
2963e12c5d1SDavid du Colombier for(;;) {
2973e12c5d1SDavid du Colombier if(c == ' ' || c == '\n')
2983e12c5d1SDavid du Colombier break;
2993e12c5d1SDavid du Colombier if(c < '0' || c > '9')
3003e12c5d1SDavid du Colombier return 1;
3013e12c5d1SDavid du Colombier l = l*10 + c-'0';
3023e12c5d1SDavid du Colombier c = *(*f)++;
3033e12c5d1SDavid du Colombier }
3043e12c5d1SDavid du Colombier if(s)
3053e12c5d1SDavid du Colombier l = -l;
3063e12c5d1SDavid du Colombier *p = l;
3073e12c5d1SDavid du Colombier return 0;
3083e12c5d1SDavid du Colombier }
309