Goto sanos source index
//
// time.c
//
// Time routines
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#ifndef KERNEL
#include <os.h>
#include <unistd.h>
#endif
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#define YEAR0 1900
#define EPOCH_YR 1970
#define SECS_DAY (24L * 60L * 60L)
#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
#define FIRSTSUNDAY(timp) (((timp)->tm_yday - (timp)->tm_wday + 420) % 7)
#define FIRSTDAYOF(timp) (((timp)->tm_wday - (timp)->tm_yday + 420) % 7)
#define TIME_MAX 2147483647L
int _daylight = 0; // Non-zero if daylight savings time is used
long _dstbias = 0; // Offset for Daylight Saving Time
long _timezone = 0; // Difference in seconds between GMT and local time
char *_tzname[2] = {"GMT", "GMT"}; // Standard/daylight savings time zone names
const char *_days[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
const char *_days_abbrev[] = {
"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"
};
const char *_months[] = {
"January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"
};
const char *_months_abbrev[] = {
"Jan", "Feb", "Mar",
"Apr", "May", "Jun",
"Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
const int _ytab[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
struct tm *gmtime_r(const time_t *timer, struct tm *tmbuf) {
time_t time = *timer;
unsigned long dayclock, dayno;
int year = EPOCH_YR;
dayclock = (unsigned long) time % SECS_DAY;
dayno = (unsigned long) time / SECS_DAY;
tmbuf->tm_sec = dayclock % 60;
tmbuf->tm_min = (dayclock % 3600) / 60;
tmbuf->tm_hour = dayclock / 3600;
tmbuf->tm_wday = (dayno + 4) % 7; // Day 0 was a thursday
while (dayno >= (unsigned long) YEARSIZE(year)) {
dayno -= YEARSIZE(year);
year++;
}
tmbuf->tm_year = year - YEAR0;
tmbuf->tm_yday = dayno;
tmbuf->tm_mon = 0;
while (dayno >= (unsigned long) _ytab[LEAPYEAR(year)][tmbuf->tm_mon]) {
dayno -= _ytab[LEAPYEAR(year)][tmbuf->tm_mon];
tmbuf->tm_mon++;
}
tmbuf->tm_mday = dayno + 1;
tmbuf->tm_isdst = 0;
tmbuf->tm_gmtoff = 0;
tmbuf->tm_zone = "UTC";
return tmbuf;
}
struct tm *localtime_r(const time_t *timer, struct tm *tmbuf) {
time_t t;
t = *timer - _timezone;
return gmtime_r(&t, tmbuf);
}
#ifndef KERNEL
struct tm *gmtime(const time_t *timer) {
return gmtime_r(timer, &gettib()->tmbuf);
}
struct tm *localtime(const time_t *timer) {
return localtime_r(timer, &gettib()->tmbuf);
}
#endif
time_t mktime(struct tm *tmbuf) {
long day, year;
int tm_year;
int yday, month;
/*unsigned*/ long seconds;
int overflow;
long dst;
tmbuf->tm_min += tmbuf->tm_sec / 60;
tmbuf->tm_sec %= 60;
if (tmbuf->tm_sec < 0) {
tmbuf->tm_sec += 60;
tmbuf->tm_min--;
}
tmbuf->tm_hour += tmbuf->tm_min / 60;
tmbuf->tm_min = tmbuf->tm_min % 60;
if (tmbuf->tm_min < 0) {
tmbuf->tm_min += 60;
tmbuf->tm_hour--;
}
day = tmbuf->tm_hour / 24;
tmbuf->tm_hour= tmbuf->tm_hour % 24;
if (tmbuf->tm_hour < 0) {
tmbuf->tm_hour += 24;
day--;
}
tmbuf->tm_year += tmbuf->tm_mon / 12;
tmbuf->tm_mon %= 12;
if (tmbuf->tm_mon < 0) {
tmbuf->tm_mon += 12;
tmbuf->tm_year--;
}
day += (tmbuf->tm_mday - 1);
while (day < 0) {
if(--tmbuf->tm_mon < 0) {
tmbuf->tm_year--;
tmbuf->tm_mon = 11;
}
day += _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
}
while (day >= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon]) {
day -= _ytab[LEAPYEAR(YEAR0 + tmbuf->tm_year)][tmbuf->tm_mon];
if (++(tmbuf->tm_mon) == 12) {
tmbuf->tm_mon = 0;
tmbuf->tm_year++;
}
}
tmbuf->tm_mday = day + 1;
year = EPOCH_YR;
if (tmbuf->tm_year < year - YEAR0) return (time_t) -1;
seconds = 0;
day = 0; // Means days since day 0 now
overflow = 0;
// Assume that when day becomes negative, there will certainly
// be overflow on seconds.
// The check for overflow needs not to be done for leapyears
// divisible by 400.
// The code only works when year (1970) is not a leapyear.
tm_year = tmbuf->tm_year + YEAR0;
if (TIME_MAX / 365 < tm_year - year) overflow++;
day = (tm_year - year) * 365;
if (TIME_MAX - day < (tm_year - year) / 4 + 1) overflow++;
day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4);
day -= (tm_year - year) / 100 + ((tm_year % 100) && tm_year % 100 < year % 100);
day += (tm_year - year) / 400 + ((tm_year % 400) && tm_year % 400 < year % 400);
yday = month = 0;
while (month < tmbuf->tm_mon) {
yday += _ytab[LEAPYEAR(tm_year)][month];
month++;
}
yday += (tmbuf->tm_mday - 1);
if (day + yday < 0) overflow++;
day += yday;
tmbuf->tm_yday = yday;
tmbuf->tm_wday = (day + 4) % 7; // Day 0 was thursday (4)
seconds = ((tmbuf->tm_hour * 60L) + tmbuf->tm_min) * 60L + tmbuf->tm_sec;
if ((TIME_MAX - seconds) / SECS_DAY < day) overflow++;
seconds += day * SECS_DAY;
// Now adjust according to timezone and daylight saving time
if (((_timezone > 0) && (TIME_MAX - _timezone < seconds)) ||
((_timezone < 0) && (seconds < -_timezone))) {
overflow++;
}
seconds += _timezone;
if (tmbuf->tm_isdst) {
dst = _dstbias;
} else {
dst = 0;
}
if (dst > seconds) overflow++; // dst is always non-negative
seconds -= dst;
if (overflow) return (time_t) -1;
if ((time_t) seconds != seconds) return (time_t) -1;
return (time_t) seconds;
}
#if !defined(KERNEL) && !defined(OS_LIB)
char *asctime_r(const struct tm *tm, char *buf) {
strftime(buf, ASCBUFSIZE, "%c\n", tm);
return buf;
}
char *ctime_r(const time_t *timer, char *buf) {
return asctime_r(localtime(timer), buf);
}
char *asctime(const struct tm *tm) {
return asctime_r(tm, gettib()->ascbuf);
}
char *ctime(const time_t *timer) {
return asctime(localtime(timer));
}
char *_strdate(char *s) {
time_t now;
time(&now);
strftime(s, 9, "%D", localtime(&now));
return s;
}
char *_strtime(char *s) {
time_t now;
time(&now);
strftime(s, 9, "%T", localtime(&now));
return s;
}
void _tzset() {
}
int usleep(useconds_t usec) {
if (msleep(usec / 1000) > 0) {
errno = EINTR;
return -1;
}
return 0;
}
int nanosleep(const struct timespec *req, struct timespec *rem) {
int rc;
rc = msleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
if (rc > 0) {
if (rem) {
rem->tv_sec = rc / 1000;
rem->tv_nsec = (rc % 1000) * 1000000;
}
errno = EINTR;
return -1;
}
return rc;
}
int getitimer(int which, struct itimerval *value) {
// TODO implement
return -1;
}
int setitimer(int which, const struct itimerval *value, struct itimerval *oldvalue) {
// TODO implement
return -1;
}
#endif