Minix1.5/lib/ansi/ctime.c

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

#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);
}