249 lines
5.1 KiB
C
249 lines
5.1 KiB
C
|
/*
|
||
|
* mktm_r.c
|
||
|
* Original Author: Adapted from tzcode maintained by Arthur David Olson.
|
||
|
* Modifications: Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
|
||
|
*
|
||
|
* Converts the calendar time pointed to by tim_p into a broken-down time
|
||
|
* expressed as local time. Returns a pointer to a structure containing the
|
||
|
* broken-down time.
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <time.h>
|
||
|
#include "local.h"
|
||
|
|
||
|
static _CONST int mon_lengths[2][MONSPERYEAR] = {
|
||
|
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||
|
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||
|
} ;
|
||
|
|
||
|
static _CONST int year_lengths[2] = {
|
||
|
365,
|
||
|
366
|
||
|
} ;
|
||
|
|
||
|
struct tm *
|
||
|
_DEFUN (_mktm_r, (tim_p, res, is_gmtime),
|
||
|
_CONST time_t * tim_p _AND
|
||
|
struct tm *res _AND
|
||
|
int is_gmtime)
|
||
|
{
|
||
|
long days, rem;
|
||
|
time_t lcltime;
|
||
|
int i;
|
||
|
int y;
|
||
|
int yleap;
|
||
|
_CONST int *ip;
|
||
|
|
||
|
/* base decision about std/dst time on current time */
|
||
|
lcltime = *tim_p;
|
||
|
|
||
|
days = ((long)lcltime) / SECSPERDAY;
|
||
|
rem = ((long)lcltime) % SECSPERDAY;
|
||
|
while (rem < 0)
|
||
|
{
|
||
|
rem += SECSPERDAY;
|
||
|
--days;
|
||
|
}
|
||
|
while (rem >= SECSPERDAY)
|
||
|
{
|
||
|
rem -= SECSPERDAY;
|
||
|
++days;
|
||
|
}
|
||
|
|
||
|
/* compute hour, min, and sec */
|
||
|
res->tm_hour = (int) (rem / SECSPERHOUR);
|
||
|
rem %= SECSPERHOUR;
|
||
|
res->tm_min = (int) (rem / SECSPERMIN);
|
||
|
res->tm_sec = (int) (rem % SECSPERMIN);
|
||
|
|
||
|
/* compute day of week */
|
||
|
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
|
||
|
res->tm_wday += DAYSPERWEEK;
|
||
|
|
||
|
/* compute year & day of year */
|
||
|
y = EPOCH_YEAR;
|
||
|
if (days >= 0)
|
||
|
{
|
||
|
for (;;)
|
||
|
{
|
||
|
yleap = isleap(y);
|
||
|
if (days < year_lengths[yleap])
|
||
|
break;
|
||
|
y++;
|
||
|
days -= year_lengths[yleap];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
--y;
|
||
|
yleap = isleap(y);
|
||
|
days += year_lengths[yleap];
|
||
|
} while (days < 0);
|
||
|
}
|
||
|
|
||
|
res->tm_year = y - YEAR_BASE;
|
||
|
res->tm_yday = days;
|
||
|
ip = mon_lengths[yleap];
|
||
|
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
|
||
|
days -= ip[res->tm_mon];
|
||
|
res->tm_mday = days + 1;
|
||
|
|
||
|
if (!is_gmtime)
|
||
|
{
|
||
|
int offset;
|
||
|
int hours, mins, secs;
|
||
|
|
||
|
TZ_LOCK;
|
||
|
if (_daylight)
|
||
|
{
|
||
|
if (y == __tzyear || __tzcalc_limits (y))
|
||
|
res->tm_isdst = (__tznorth
|
||
|
? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)
|
||
|
: (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));
|
||
|
else
|
||
|
res->tm_isdst = -1;
|
||
|
}
|
||
|
else
|
||
|
res->tm_isdst = 0;
|
||
|
|
||
|
offset = (res->tm_isdst == 1 ? __tzrule[1].offset : __tzrule[0].offset);
|
||
|
|
||
|
hours = offset / SECSPERHOUR;
|
||
|
offset = offset % SECSPERHOUR;
|
||
|
|
||
|
mins = offset / SECSPERMIN;
|
||
|
secs = offset % SECSPERMIN;
|
||
|
|
||
|
res->tm_sec -= secs;
|
||
|
res->tm_min -= mins;
|
||
|
res->tm_hour -= hours;
|
||
|
|
||
|
if (res->tm_sec >= SECSPERMIN)
|
||
|
{
|
||
|
res->tm_min += 1;
|
||
|
res->tm_sec -= SECSPERMIN;
|
||
|
}
|
||
|
else if (res->tm_sec < 0)
|
||
|
{
|
||
|
res->tm_min -= 1;
|
||
|
res->tm_sec += SECSPERMIN;
|
||
|
}
|
||
|
if (res->tm_min >= MINSPERHOUR)
|
||
|
{
|
||
|
res->tm_hour += 1;
|
||
|
res->tm_min -= MINSPERHOUR;
|
||
|
}
|
||
|
else if (res->tm_min < 0)
|
||
|
{
|
||
|
res->tm_hour -= 1;
|
||
|
res->tm_min += MINSPERHOUR;
|
||
|
}
|
||
|
if (res->tm_hour >= HOURSPERDAY)
|
||
|
{
|
||
|
++res->tm_yday;
|
||
|
++res->tm_wday;
|
||
|
if (res->tm_wday > 6)
|
||
|
res->tm_wday = 0;
|
||
|
++res->tm_mday;
|
||
|
res->tm_hour -= HOURSPERDAY;
|
||
|
if (res->tm_mday >= ip[res->tm_mon])
|
||
|
{
|
||
|
res->tm_mday -= ip[res->tm_mon] - 1;
|
||
|
res->tm_mon += 1;
|
||
|
if (res->tm_mon == 12)
|
||
|
{
|
||
|
res->tm_mon = 0;
|
||
|
res->tm_year += 1;
|
||
|
res->tm_yday = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (res->tm_hour < 0)
|
||
|
{
|
||
|
res->tm_yday -= 1;
|
||
|
res->tm_wday -= 1;
|
||
|
if (res->tm_wday < 0)
|
||
|
res->tm_wday = 6;
|
||
|
res->tm_mday -= 1;
|
||
|
res->tm_hour += 24;
|
||
|
if (res->tm_mday == 0)
|
||
|
{
|
||
|
res->tm_mon -= 1;
|
||
|
if (res->tm_mon < 0)
|
||
|
{
|
||
|
res->tm_mon = 11;
|
||
|
res->tm_year -= 1;
|
||
|
res->tm_yday = 365 + isleap(res->tm_year);
|
||
|
}
|
||
|
res->tm_mday = ip[res->tm_mon];
|
||
|
}
|
||
|
}
|
||
|
TZ_UNLOCK;
|
||
|
}
|
||
|
else
|
||
|
res->tm_isdst = 0;
|
||
|
|
||
|
return (res);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
_DEFUN (__tzcalc_limits, (year),
|
||
|
int year)
|
||
|
{
|
||
|
int days, year_days, years;
|
||
|
int i, j;
|
||
|
|
||
|
if (year < EPOCH_YEAR)
|
||
|
return 0;
|
||
|
|
||
|
__tzyear = year;
|
||
|
|
||
|
years = (year - EPOCH_YEAR);
|
||
|
|
||
|
year_days = years * 365 +
|
||
|
(years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
|
||
|
(years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
|
||
|
|
||
|
for (i = 0; i < 2; ++i)
|
||
|
{
|
||
|
if (__tzrule[i].ch == 'J')
|
||
|
days = year_days + __tzrule[i].d + (isleap(year) && __tzrule[i].d >= 60);
|
||
|
else if (__tzrule[i].ch == 'D')
|
||
|
days = year_days + __tzrule[i].d;
|
||
|
else
|
||
|
{
|
||
|
int yleap = isleap(year);
|
||
|
int m_day, m_wday, wday_diff;
|
||
|
_CONST int *ip = mon_lengths[yleap];
|
||
|
|
||
|
days = year_days;
|
||
|
|
||
|
for (j = 1; j < __tzrule[i].m; ++j)
|
||
|
days += ip[j-1];
|
||
|
|
||
|
m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
|
||
|
|
||
|
wday_diff = __tzrule[i].d - m_wday;
|
||
|
if (wday_diff < 0)
|
||
|
wday_diff += DAYSPERWEEK;
|
||
|
m_day = (__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
|
||
|
|
||
|
while (m_day >= ip[j])
|
||
|
m_day -= DAYSPERWEEK;
|
||
|
|
||
|
days += m_day;
|
||
|
}
|
||
|
|
||
|
/* store the change-over time in GMT form by adding offset */
|
||
|
__tzrule[i].change = days * SECSPERDAY + __tzrule[i].s + __tzrule[i].offset;
|
||
|
}
|
||
|
|
||
|
__tznorth = (__tzrule[0].change < __tzrule[1].change);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|