Minix1.5/lib/ansi/ctime.c
#include <lib.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define toint(X) (X - '0')
PRIVATE char timebuf[26];
PRIVATE char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
PRIVATE char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
void tzset();
char *asctime(time)
register _CONST struct tm *time;
/*
* Convert <time> structure value to a string. The same format, and
* the same internal buffer, as for ctime() is used for this function.
*/
{
if (time == (struct tm *)NULL)
strcpy(timebuf, "??? ??? ?? ??:??:?? ????\n");
else
sprintf(timebuf, "%.3s %.3s%3d %02d:%02d:%02d %04d\n",
day[time->tm_wday], month[time->tm_mon], time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec, 1900+time->tm_year);
return(timebuf);
}
char *ctime(rawtime)
_CONST time_t *rawtime;
/*
* Convert <rawtime> to a string. A 26 character fixed field string
* is created from the raw time value. The following is an example
* of what this string might look like:
* "Wed Jul 08 18:43:07 1987\n\0"
* A 24-hour clock is used, and due to a limitation in the ST system
* clock value, only a resolution of 2 seconds is possible. A pointer
* to the formatted string, which is held in an internal buffer, is
* returned.
*/
{
return(asctime(localtime(rawtime)));
}
/* mktime, localtime, gmtime */
/* written by ERS and placed in the public domain */
#define SECS_PER_MIN (60L)
#define SECS_PER_HOUR (60*SECS_PER_MIN)
#define SECS_PER_DAY (24*SECS_PER_HOUR)
#define SECS_PER_YEAR (365*SECS_PER_DAY)
#define SECS_PER_LEAPYEAR (SECS_PER_DAY + SECS_PER_YEAR)
PRIVATE
int days_per_mth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
PRIVATE _PROTOTYPE( time_t tzoffset, (char *s, int *hasdst));
PRIVATE _PROTOTYPE( int indst, (_CONST struct tm *t));
time_t timezone = -1; /* holds # seconds west of GMT */
PRIVATE int dst = -1; /* whether dst holds in current timezone */
/*
* FIXME: none of these routines is very efficient. Also, none of them
* handle dates before Jan 1, 1970.
*
*/
/*
* mktime: take a time structure representing the local time (such as is
* returned by localtime() and convert it into the standard representation
* (as seconds since midnight Jan. 1 1970, GMT).
*
*/
time_t mktime(t)
_CONST struct tm *t;
{
time_t s;
int y;
y = t->tm_year - 70;
if (y < 0) /* year before 1970 */
return (time_t) -1;
s = (SECS_PER_YEAR * y) + ( ((y+1)/4) * SECS_PER_DAY);
/* extra days for leap years */
if ( (y+2)%4 )
days_per_mth[1] = 28;
else
days_per_mth[1] = 29;
for (y = 0; y < t->tm_mon; y++)
s += SECS_PER_DAY * days_per_mth[y];
s += (t->tm_mday - 1) * SECS_PER_DAY;
s += t->tm_hour * SECS_PER_HOUR;
s += t->tm_min * SECS_PER_MIN;
s += t->tm_sec;
/* Now adjust for the time zone and possible daylight savings time */
if (timezone == -1)
tzset();
s += timezone;
if (dst == 1 && indst(t))
s -= SECS_PER_HOUR;
return s;
}
PRIVATE struct tm the_time;
struct tm *gmtime(t)
_CONST time_t *t;
{
struct tm *stm = &the_time;
time_t time = *t;
int year, mday, i;
if (time < 0) /* negative times are bad */
return 0;
stm->tm_wday = ((time/SECS_PER_DAY) + 4) % 7;
year = 70;
for (;;) {
if (time < SECS_PER_YEAR) break;
if ((year % 4) == 0) {
if (time < SECS_PER_LEAPYEAR)
break;
else
time -= SECS_PER_LEAPYEAR;
}
else
time -= SECS_PER_YEAR;
year++;
}
stm->tm_year = year;
mday = stm->tm_yday = time/SECS_PER_DAY;
days_per_mth[1] = (year % 4) ? 28 : 29;
for (i = 0; mday >= days_per_mth[i]; i++)
mday -= days_per_mth[i];
stm->tm_mon = i;
stm->tm_mday = mday + 1;
time = time % SECS_PER_DAY;
stm->tm_hour = time/SECS_PER_HOUR;
time = time % SECS_PER_HOUR;
stm->tm_min = time/SECS_PER_MIN;
stm->tm_sec = time % SECS_PER_MIN;
stm->tm_isdst = 0;
return stm;
}
/* given a standard time, convert it to a local time */
struct tm *localtime(t)
_CONST time_t *t;
{
struct tm *stm;
time_t offset; /* seconds between local time and GMT */
if (timezone == -1) tzset();
offset = *t - timezone;
stm = gmtime(&offset);
if (stm == (struct tm *)NULL) return stm; /* check for illegal time */
stm->tm_isdst = (dst == -1) ? -1 : 0;
if (dst == 1 && indst(stm)) { /* daylight savings time in effect */
stm->tm_isdst = 1;
if (++stm->tm_hour > 23) {
stm->tm_hour -= 24;
stm->tm_wday = (stm->tm_wday + 1) % 7;
stm->tm_yday++;
stm->tm_mday++;
if (stm->tm_mday > days_per_mth[stm->tm_mon]) {
stm->tm_mday = 1;
stm->tm_mon++;
}
}
}
return stm;
}
/* set the timezone and dst flag to the local rules */
void tzset()
{
timezone = tzoffset(getenv("TZ"), &dst);
}
/*
* determine the difference, in seconds, between the given time zone
* and Greenwich Mean. As a side effect, the integer pointed to
* by hasdst is set to 1 if the given time zone follows daylight
* savings time, 0 if there is no DST.
*
* Time zones are given as strings of the form
* "[TZNAME][h][:m][TZDSTNAME]" where h:m gives the hours:minutes
* east of GMT for the timezone (if [:m] does not appear, 0 is assumed).
* If the final field, TZDSTNAME, appears, then the time zone follows
* daylight savings time.
*
* Example: EST5EDT would represent the N. American Eastern time zone
* CST6CDT would represent the N. American Central time zone
* NFLD3:30NFLD would represent Newfoundland time (one and a
* half hours ahead of Eastern).
* OZCST-9:30 would represent the Australian central time zone.
* (which, so I hear, doesn't have DST).
*
* NOTE: support for daylight savings time is currently very bogus.
* It's probably best to do without, unless you live in North America.
*
*/
PRIVATE time_t tzoffset(s, hasdst)
char *s;
int *hasdst;
{
time_t off = 0;
int x, sgn = 1;
*hasdst = -1; /* Assume unknown */
if (!s || !*s)
return 0; /* Assume GMT */
*hasdst = 0;
while (isalpha(*s)) s++; /* skip name */
x = 0;
if (*s == '-') {
sgn = -1;
s++;
}
while (isdigit(*s)) {
x = 10 * x + toint(*s);
s++;
}
off = x * SECS_PER_HOUR;
if (*s == ':') {
x = 0;
s++;
while (isdigit(*s)) {
x = 10 * x + toint(*s);
s++;
}
off += (x * SECS_PER_MIN);
}
if (isalpha(*s))
*hasdst = 1;
return sgn * off;
}
/*
* Given a tm struct representing the local time, determine whether
* DST is currently in effect. This should only be
* called if it is known that the time zone indeed supports DST.
*
* FIXME: For now, assume that everyone follows the North American
* time zone rules, all the time. This means daylight savings
* time is assumed to be in effect from the first Sunday in April
* to the last Sunday in October. Prior to 1987, the old rules
* (last Sunday in April to last Sunday in Oct.) are used, even when
* (as in 1974) they're not applicable. Sorry.
*
*/
PRIVATE int indst(t)
_CONST struct tm *t;
{
if (t->tm_mon == 3) { /* April */
/* before 1987, see if there's another sunday in the month */
if (t->tm_year < 87 && t->tm_wday + 30 - t->tm_mday < 7)
return 1; /* no there isn't */
/* after 1987, see if a sunday has happened yet */
if (t->tm_wday - t->tm_mday < 0)
return 1; /* yep */
return 0;
}
if (t->tm_mon == 9) { /* October */
if (t->tm_wday + 31 - t->tm_mday < 7)
return 0; /* there are no more sundays */
return 1;
}
/* Otherwise, see if it's a month between April and October exclusive */
return (t->tm_mon > 3 && t->tm_mon < 9);
}
/* return difference between two time_t types -- ERS*/
double difftime(t1, t2)
time_t t1, t2;
{
return (double) (t2 - t1);
}