home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
mint
/
mntlib16.lzh
/
MNTLIB16
/
LOCALTIM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
9KB
|
325 lines
/* mktime, localtime, gmtime */
/* written by ERS and placed in the public domain */
#include <stddef.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#ifndef _COMPILER_H
#include <compiler.h>
#endif
#if 0
static void
DEBUG_TM(nm, tm)
char *nm;
struct tm *tm;
{
char buf[100];
(void)strftime(buf, 100, "%c %z", tm);
printf("%s: %s\n", nm, buf);
}
#else
#define DEBUG_TM(nm, tm)
#endif
#define SECS_PER_MIN (60L)
#define SECS_PER_HOUR (3600L)
#define SECS_PER_DAY (86400L)
#define SECS_PER_YEAR (31536000L)
#define SECS_PER_LEAPYEAR (SECS_PER_DAY + SECS_PER_YEAR)
time_t _timezone = -1; /* holds # seconds west of GMT */
static int
days_per_mth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static int
mth_start[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
static time_t tzoffset __PROTO((char *s, int *hasdst));
static int indst __PROTO((const struct tm *t));
static 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).
*
* Note that time() sends us such a structure with tm_yday undefined, so
* we shouldn't count on tm_yday being correct.
*/
time_t
mktime(t)
const struct tm *t;
{
time_t s;
int y;
DEBUG_TM("mktime", t);
if (t->tm_year < 70) /* year before 1970 */
return (time_t) -1;
/* calculate tm_yday here */
y = (t->tm_mday - 1) + mth_start[t->tm_mon] + /* leap year correction */
( ( (t->tm_year % 4) != 0 ) ? 0 : (t->tm_mon > 1) );
s = (t->tm_sec)+(t->tm_min*SECS_PER_MIN)+(t->tm_hour*SECS_PER_HOUR) +
(y*SECS_PER_DAY)+((t->tm_year - 70)*SECS_PER_YEAR) +
((t->tm_year - 69)/4)*SECS_PER_DAY;
/* Now adjust for the time zone and possible daylight savings time */
/* note that we have to call tzset() every time; see 1003.1 sect 8.1.1 */
tzset();
s += _timezone;
if (dst == 1 && indst(t))
s -= 3600;
return s;
}
struct tm *_gmtime(t, stm)
const time_t *t;
struct tm *stm;
{
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;
DEBUG_TM("gmtime", stm);
return stm;
}
struct tm *gmtime(t)
const time_t *t;
{
static struct tm gtime;
return _gmtime(t, >ime);
}
/* given a standard time, convert it to a local time */
struct tm *localtime(t)
const time_t *t;
{
static struct tm ltim;
struct tm *stm;
time_t offset; /* seconds between local time and GMT */
tzset();
offset = *t - _timezone;
stm = _gmtime(&offset, <im);
if (stm == NULL) return stm; /* check for illegal time */
stm->tm_isdst = (dst == -1) ? -1 : 0;
if (dst == 1 && indst((const struct tm *)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++;
}
}
}
DEBUG_TM("localtime", stm);
return stm;
}
/*
* THIS IS A DELIBERATE VIOLATION OF THE ANSI STANDARD:
* there appears to be a conflict between Posix and ANSI; the former
* mandates a "tzset()" function that gets called whenever time()
* does, and which sets some global variables. ANSI wants none of
* this. Several Unix implementations have tzset(), and few people are
* going to be hurt by it, so it's included here.
*/
/* set the timezone and dst flag to the local rules. Also sets the
global variable tzname to the names of the timezones
*/
char *tzname[2] = {"UCT", "UCT"};
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.
*
*/
#define TZNAMLEN 8 /* max. length of time zone name */
static
time_t
tzoffset(s, hasdst)
char *s;
int *hasdst;
{
time_t off = 0;
int x, sgn = 1;
static char stdname[TZNAMLEN+1], dstname[TZNAMLEN+1];
static char unknwn[4] = "???";
char *n;
*hasdst = -1; /* Assume unknown */
if (!s || !*s)
return 0; /* Assume GMT */
*hasdst = 0;
n = stdname;
while (*s && isalpha(*s)) {
*n++ = *s++; /* skip name */
}
*n++ = 0;
/* now figure out the offset */
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);
}
n = dstname;
if (isalpha(*s)) {
*hasdst = 1;
while (*s && isalpha(*s)) *n++ = *s++;
}
*n++ = 0;
if (stdname[0])
tzname[0] = stdname;
else
tzname[0] = unknwn;
if (dstname[0])
tzname[1] = dstname;
else
tzname[1] = stdname;
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.
*
*/
static
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);
}