#include "time.h"
static const int mdays_common[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int mdays_leap[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int month_start_common[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
static const int month_start_leap[12] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
#define is_leap(year) ((((year) % 4 == 0 && (year) % 100 != 0)) || ((year) % 400 == 0))
#define ydays(year) (is_leap(year) ? 366 : 365)
#define mdays(year, mon) (is_leap(year) ? mdays_leap[mon] : mdays_common[mon])
#define month_start(year) (is_leap(year) ? month_start_leap : month_start_common)
#define leap_years(year, n) (((n) + 1) * ((year) - 1) / (n) - (year))
#define year_wday(year) ((1 + (year) + (leap_years((year), 4) - leap_years((year), 100) + leap_years((year), 400))) % 7)
#define wday(year, yday) ((year_wday(year) + (yday)) % 7)
#define dsecs 86400
static long ysec(const struct dst_date_struct *dst_date, int year)
{
int mon;
int mon_yday;
long msec;
int wday;
int mday;
int mweek;
int i, mdays;
mon = dst_date->mon;
mon_yday = month_start(year)[mon];
msec = 0;
wday = wday(year, mon_yday);
mday = 0;
mweek = 0;
for (i = 0, mdays = mdays(year, mon); i < mdays; i++) {
if (wday == dst_date->wday) {
mweek++;
mday = i;
}
if (mweek == dst_date->mweek)
break;
msec += dsecs;
wday = (wday + 1) % 7;
}
return (mon_yday + mday) * dsecs + dst_date->time;
}
static int is_dst(const time_t *timep, const struct tz_struct *tz)
{
time_t t;
int year;
time_t dst_start, dst_end;
long ysecs;
if (!tz->dst)
return 0;
t = 0;
year = 1970;
if (*timep < 0)
do
year--, t -= ydays(year) * dsecs;
while (*timep < t);
else
while (*timep >= t + (ysecs = ydays(year) * dsecs))
t += ysecs, year++;
dst_start = t + tz->offset + ysec(&tz->dst->start, year);
dst_end = t + tz->dst->offset + ysec(&tz->dst->end, year);
return dst_start < dst_end
? *timep >= dst_start && *timep < dst_end
: *timep < dst_start || *timep >= dst_end;
}
struct tm *__make_tm(const time_t *timep, const struct tz_struct *tz, struct tm *result)
{
int sec;
int min;
int hour;
int mday;
int mon;
int year;
int wday;
int yday;
int isdst;
long day, dsec;
const int *month_start;
register int ydays;
isdst = is_dst(timep, tz);
day = *timep / dsecs;
dsec = *timep % dsecs;
dsec -= isdst ? tz->dst->offset : tz->offset;
if (dsec < 0)
do
day--, dsec += dsecs;
while (dsec < 0);
else while (dsec >= dsecs)
dsec -= dsecs, day++;
year = 1970;
if (day < 0)
do
year--, day += ydays(year);
while (day < 0);
else
while (day >= (ydays = ydays(year)))
day -= ydays, year++;
yday = day;
wday = wday(year, yday);
mon = 0;
month_start = month_start(year);
while (mon < 11 && yday >= month_start[mon + 1])
mon++;
mday = yday - month_start[mon];
hour = dsec / 3600;
min = dsec / 60 % 60;
sec = dsec % 60;
result->tm_sec = sec;
result->tm_min = min;
result->tm_hour = hour;
result->tm_mday = mday + 1;
result->tm_mon = mon;
result->tm_year = year - 1900;
result->tm_wday = wday;
result->tm_yday = yday;
result->tm_isdst = isdst;
return result;
}
#define normalize(var1, max, var2) ({ \
register int _tmp; \
if (var1 < 0) { \
_tmp = (max - var1) / max; \
var2 -= _tmp; \
var1 += _tmp * max; \
} \
else if (var1 >= max) { \
_tmp = var1 / max; \
var2 += _tmp; \
var1 -= _tmp * max; \
} \
})
time_t __make_time(struct tm *tm, const struct tz_struct *tz)
{
int sec;
int min;
int hour;
int mday;
int mon;
int year;
int wday;
int yday;
int isdst;
int mdays;
long t;
int y;
time_t tloc;
sec = tm->tm_sec;
min = tm->tm_min;
hour = tm->tm_hour;
mday = tm->tm_mday - 1;
mon = tm->tm_mon;
year = tm->tm_year + 1900;
isdst = tm->tm_isdst;
normalize(sec, 60, min);
normalize(min, 60, hour);
normalize(hour, 24, mday);
normalize(mon, 12, year);
if (mday < 0)
do {
if (mon > 0)
mon--;
else
year--, mon = 11;
mday += mdays(year, mon);
}
while (mday < 0);
else
while (mday >= (mdays = mdays(year, mon))) {
mday -= mdays;
if (mon < 11)
mon++;
else
year++, mon = 0;
}
yday = month_start(year)[mon] + mday;
wday = wday(year, yday);
t = hour * 3600 + min * 60 + sec;
t += yday * dsecs;
if (year < 1970)
for (y = 1970; y > year; y--, t -= ydays(y) * dsecs);
else
for (y = 1970; y < year; t += ydays(y) * dsecs, y++);
if (isdst < 0) {
tloc = t + tz->offset;
isdst = is_dst(&tloc, tz);
}
t += isdst && tz->dst ? tz->dst->offset : tz->offset;
tm->tm_sec = sec;
tm->tm_min = min;
tm->tm_hour = hour;
tm->tm_mday = mday + 1;
tm->tm_mon = mon;
tm->tm_year = year - 1900;
tm->tm_wday = wday;
tm->tm_yday = yday;
tm->tm_isdst = isdst;
return t;
}