149 lines
3.3 KiB
C
149 lines
3.3 KiB
C
/*
|
|
* mktime - convert local time into calendar time
|
|
*/
|
|
/* $Id$ */
|
|
|
|
#include <time.h>
|
|
#include <limits.h>
|
|
#include "loc_time.h"
|
|
|
|
/* The code assumes that unsigned long can be converted to time_t.
|
|
* A time_t should not be wider than unsigned long, since this would mean
|
|
* that the check for overflow at the end could fail.
|
|
*/
|
|
time_t
|
|
mktime(register struct tm* timep)
|
|
{
|
|
register long day, year;
|
|
register int tm_year;
|
|
int yday, month;
|
|
register unsigned long seconds;
|
|
int overflow;
|
|
unsigned dst;
|
|
|
|
timep->tm_min += timep->tm_sec / 60;
|
|
timep->tm_sec %= 60;
|
|
if (timep->tm_sec < 0)
|
|
{
|
|
timep->tm_sec += 60;
|
|
timep->tm_min--;
|
|
}
|
|
timep->tm_hour += timep->tm_min / 60;
|
|
timep->tm_min = timep->tm_min % 60;
|
|
if (timep->tm_min < 0)
|
|
{
|
|
timep->tm_min += 60;
|
|
timep->tm_hour--;
|
|
}
|
|
day = timep->tm_hour / 24;
|
|
timep->tm_hour = timep->tm_hour % 24;
|
|
if (timep->tm_hour < 0)
|
|
{
|
|
timep->tm_hour += 24;
|
|
day--;
|
|
}
|
|
timep->tm_year += timep->tm_mon / 12;
|
|
timep->tm_mon %= 12;
|
|
if (timep->tm_mon < 0)
|
|
{
|
|
timep->tm_mon += 12;
|
|
timep->tm_year--;
|
|
}
|
|
day += (timep->tm_mday - 1);
|
|
while (day < 0)
|
|
{
|
|
day += YEARSIZE(YEAR0 + timep->tm_year - 1);
|
|
timep->tm_year--;
|
|
}
|
|
while (day >= YEARSIZE(YEAR0 + timep->tm_year))
|
|
{
|
|
day -= YEARSIZE(YEAR0 + timep->tm_year);
|
|
timep->tm_year++;
|
|
}
|
|
while (day >= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon])
|
|
{
|
|
day -= _ytab[LEAPYEAR(YEAR0 + timep->tm_year)][timep->tm_mon];
|
|
if (++(timep->tm_mon) == 12)
|
|
{
|
|
timep->tm_mon = 0;
|
|
timep->tm_year++;
|
|
}
|
|
}
|
|
timep->tm_mday = day + 1;
|
|
_tzset(); /* set timezone and dst info */
|
|
year = EPOCH_YR;
|
|
if (timep->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.
|
|
*/
|
|
#if EPOCH_YR != 1970
|
|
#error EPOCH_YR != 1970
|
|
#endif
|
|
tm_year = timep->tm_year + YEAR0;
|
|
|
|
if (LONG_MAX / 365 < tm_year - year)
|
|
overflow++;
|
|
day = (tm_year - year) * 365;
|
|
if (LONG_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 < timep->tm_mon)
|
|
{
|
|
yday += _ytab[LEAPYEAR(tm_year)][month];
|
|
month++;
|
|
}
|
|
yday += (timep->tm_mday - 1);
|
|
if (day + yday < 0)
|
|
overflow++;
|
|
day += yday;
|
|
|
|
timep->tm_yday = yday;
|
|
timep->tm_wday = (day + 4) % 7; /* day 0 was thursday (4) */
|
|
|
|
seconds = ((timep->tm_hour * 60L) + timep->tm_min) * 60L + timep->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 (timep->tm_isdst < 0)
|
|
dst = _dstget(timep);
|
|
else if (timep->tm_isdst)
|
|
dst = _dst_off;
|
|
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;
|
|
}
|