|
|
coherent
/*
* libc/gen/ctime.c
* Convert time to ASCII representation.
*
* Pseudo system-5, employs TIMEZONE environment for gmt offset,
* timezone abbreviations, and daylight savings time information.
* TIMEZONE=SSS:mmm:DDD:n.d.m:n.d.m:h:m
* SSS - Standard timezone abbreviation up to 31 characters long
* mmm - minutes west of GMT
* DDD - Daylight timezone abbreviation also 31 characters
* n.d.m - n'th occurrence of d'th day of week in m'th month of
* start and end of daylight savings time. Negative n indicates
* counting backwards from end of month. Zero n indicates absolute date,
* d'th day of m'th month. Days and months from 1 to n.
* h - Hour of change from standard to daylight.
* m - Minutes of adjustment at change.
* Example - Central standard in current US conventions:
* TIMEZONE=CST:3600:CDT:-1.1.4:-1.1.10:2:60
* Only the first two fields are required.
* If no daylight timezone is specified, then no daylight conversion is done.
* If no dates for daylight are given, they default to 83-05-10 US standard.
* If no hour of daylight time change is specified, it defaults to 2AM.
* If no minutes of adjustment is specified, it defaults to 60.
* These defaults can be changed by overwriting tzdstdef[].
*/
#include <time.h>
#if 0
/* Required for ftime(), now conditionalized out, cf. comments below. */
#include <sys/timeb.h>
#endif
#define FEB 1
#define NWDAY 7 /* Number of weekdays */
#define NMON 12 /* Number of months */
#define todigit(c) ((c)+'0')
#define NTZNAME 31 /* max time zone name size */
/* Static data. */
static char daynames[3*NWDAY+1] = "SunMonTueWedThuFriSat";
static char dpm[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static int dstadjust = 60*60; /* In seconds */
static char dsthour = 2;
static struct dsttimes {
char dst_occur, dst_day, dst_month;
} dsttimes[2] = {
{ 1, 0, 3 }, /* First Sunday in April */
{ -1, 0, 9 } /* Last Sunday in October */
};
static char months[3*NMON+1] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char timestr[] = "AAA AAA DD DD:DD:DD DDDD\n";
static struct tm tm;
static char tz0[NTZNAME+1] = "GMT";
static char tz1[NTZNAME+1] = "";
/* Global data. */
long timezone = 0L;
char *tzname[2] = { tz0, tz1 };
char tzdstdef[] = "1.1.4:-1.1.10:2:60......";
/* Set the timezone parameters, once is enough */
void
settz()
{
extern char *getenv();
register char *cp1, *cp2;
static int settz = 0;
if (settz++ > 0)
return;
if ((cp1 = getenv("TIMEZONE")) == ((char *)0))
return;
timezone = 0;
/* Read primary timezone name and nul terminate */
cp2 = tzname[0];
while (*cp1 && *cp1 != ':' && cp2 < &tzname[0][NTZNAME])
*cp2++ = *cp1++;
*cp2++ = '\0';
while (*cp1 && *cp1++ != ':');
/* Read timezone offset and convert to seconds */
timezone = (long)atoi(cp1) * 60L;
while (*cp1 && *cp1++ != ':');
/* Read daylight timezone name and nul terminate */
cp2 = tzname[1];
while (*cp1 && *cp1 != ':' && cp2 < &tzname[1][NTZNAME])
*cp2++ = *cp1++;
*cp2++ = '\0';
while (*cp1 && *cp1++ != ':');
/* Exit if no daylight time */
if (tzname[1][0] == '\0')
return;
/* Set default dst parameters */
setdst(tzdstdef);
/* Set supplied dst parameters */
setdst(cp1);
}
/* Parse and set dst parameters */
static
setdst(cp1) register char *cp1;
{
/* Get optional start of daylight time */
if (*cp1) {
dsttimes[0].dst_occur = atoi(cp1);
while (*cp1 && *cp1++ != '.');
dsttimes[0].dst_day = atoi(cp1)-1;
while (*cp1 && *cp1++ != '.');
dsttimes[0].dst_month = atoi(cp1)-1;
while (*cp1 && *cp1++ != ':');
}
/* Get optional end of daylight time */
if (*cp1) {
dsttimes[1].dst_occur = atoi(cp1);
while (*cp1 && *cp1++ != '.');
dsttimes[1].dst_day = atoi(cp1)-1;
while (*cp1 && *cp1++ != '.');
dsttimes[1].dst_month = atoi(cp1)-1;
while (*cp1 && *cp1++ != ':');
}
/* Get optional hour of daylight time advance */
if (*cp1) {
dsthour = atoi(cp1);
while (*cp1 && *cp1++ != ':');
}
/* Get optional minutes of adjustment */
if (*cp1)
dstadjust = atoi(cp1) * 60;
}
#if 0
/*
* This ftime() is not required for COH 4.0.1r78 or later,
* it is now a system call using the stub generated by sys/i386/scall.s5.
*/
/*
* ftime()
*/
ftime (tb) struct timeb *tb;
{
time_t t;
tb->time = time(&t);
settz();
localtime(&t);
tb->millitm = 0;
tb->timezone = (short)(timezone / 60L);
tb->dstflag = isdaylight();
}
#endif
/*
* Most common interface, returns a static string
* which is a printable version of the time and date.
*/
char *
ctime(tp)
long *tp;
{
return asctime(localtime(tp));
}
/*
* Do what gmtime does for the local timezone.
* And correct for daylight time.
*/
struct tm *
localtime(tp)
long *tp;
{
long ltime;
settz();
ltime = *tp - timezone;
gmtime(<ime);
/*
* If necessary, adjust for daylight saving time.
*/
if (isdaylight()) {
ltime = *tp - timezone + dstadjust;
gmtime(<ime);
tm.tm_isdst = 1;
} else
tm.tm_isdst = 0;
return &tm;
}
/*
* Returns a printable version of the time
* which has been broken down as in the tm structure.
*/
char *
asctime(tmp)
struct tm *tmp;
{
register char *cp, *xp;
register unsigned i;
cp = timestr;
/*
* Day of week
*/
if ((i = tmp->tm_wday) >= NWDAY)
i = 0;
xp = &daynames[i*3];
*cp++ = *xp++;
*cp++ = *xp++;
*cp++ = *xp++;
*cp++ = ' ';
/*
* Month
*/
if ((i = tmp->tm_mon) >= NMON)
i = 0;
xp = &months[i*3];
*cp++ = *xp++;
*cp++ = *xp++;
*cp++ = *xp++;
*cp++ = ' ';
/*
* Day of month
*/
if ((i = tmp->tm_mday) >= 10)
*cp++ = todigit(i/10);
else
*cp++ = ' ';
*cp++ = todigit(i%10);
*cp++ = ' ';
/*
* Hours:mins:seconds
*/
*cp++ = todigit((i = tmp->tm_hour)/10);
*cp++ = todigit(i%10);
*cp++ = ':';
*cp++ = todigit((i = tmp->tm_min)/10);
*cp++ = todigit(i%10);
*cp++ = ':';
*cp++ = todigit((i = tmp->tm_sec)/10);
*cp++ = todigit(i%10);
*cp++ = ' ';
/*
* Year
*/
i = tmp->tm_year + 1900;
*cp++ = todigit(i/1000);
i = i%1000;
*cp++ = todigit(i/100);
i = i%100;
*cp++ = todigit(i/10);
*cp++ = todigit(i%10);
*cp++ = '\n';
*cp++ = '\0';
return timestr;
}
/*
* Do conversions for Greenwich Mean Time to
* the tm structure.
*/
struct tm *
gmtime(tp)
long *tp;
{
long xtime;
unsigned days;
long secs;
int year;
int ydays;
int wday;
register char *mp;
if ((xtime = *tp) < 0)
xtime = 0;
days = xtime/(60L*60L*24L);
secs = xtime%(60L*60L*24L);
tm.tm_hour = secs/(60L*60L);
secs = secs%(60L*60L);
tm.tm_min = secs/60;
tm.tm_sec = secs%60;
/*
* Start at Thursday (wday=4) Jan 1, 1970 (the Epoch)
* and calculate from there.
*/
wday = (4+days)%NWDAY;
year = 1970;
for (;;) {
ydays = isleap(year) ? 366 : 365;
if (days < ydays)
break;
year++;
days -= ydays;
}
tm.tm_year = year-1900;
tm.tm_yday = days;
tm.tm_wday = wday;
/*
* Setup february's #days now.
*/
if (isleap(year))
dpm[FEB] = 29;
else
dpm[FEB] = 28;
for (mp = &dpm[0]; mp < &dpm[NMON] && days >= *mp; mp++)
days -= *mp;
tm.tm_mon = mp-dpm;
tm.tm_mday = days+1;
return &tm;
}
/*
* Return 1 on leap years; 0 otherwise.
*/
static
isleap(yr)
register yr;
{
if (yr%4000 == 0)
return 0;
return (yr%400==0 || (yr%100!=0 && yr%4==0));
}
/*
* Check for daylight savings time.
* Watch out for the Southern Hemisphere, where start month > end month.
* This does not do the case where start == end correctly for all cases.
*/
static
isdaylight()
{
register int month, start, end, xday;
if (tzname[1][0] == 0)
return 0; /* No name, no daylight time */
month = tm.tm_mon;
start = dsttimes[0].dst_month;
end = dsttimes[1].dst_month;
if ((start <= end && (month < start || month > end))
|| (start > end && (month < start && month > end)))
return 0; /* current month is never DST */
else if (month == start) { /* DST starts this month */
xday = nthday(&dsttimes[0]); /* DST starts on xday */
if (tm.tm_mday != xday)
return (tm.tm_mday > xday);
return (tm.tm_hour >= dsthour);
} else if (month == end) { /* DST ends this month */
xday = nthday(&dsttimes[1]); /* DST ends on xday */
if (tm.tm_mday != xday)
return (tm.tm_mday < xday);
return (tm.tm_hour < dsthour-1);
} else
return 1; /* current month is always DST */
}
static
nthday(dp)
register struct dsttimes *dp;
{
register int nthday;
register int nth;
if ((nth = dp->dst_occur) == 0)
return dp->dst_day;
nthday = tm.tm_mday - tm.tm_wday + dp->dst_day;
if (nth > 0) {
while (nthday > 0)
nthday -= 7;
do
nthday += 7;
while (--nth > 0);
} else {
while (nthday < dpm[tm.tm_mon])
nthday += 7;
do
nthday -= 7;
while (++nth < 0);
}
return nthday;
}
/* end of ctime.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.