#include #include /* * Returns the number of leap years prior to the given year. */ static int leap_years(int year) { return (year-1)/4 + (year-1)/400 - (year-1)/100; } static int is_leap_year(int year) { return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } static int days_in_month(int month, int year) { static char month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, }; /* we may need to update this in the year 4000, pending a * decision on whether or not it's a leap year */ if (month == 1) return is_leap_year(year) ? 29 : 28; return month_days[month]; } static const int days_per_month[2][13] = {{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}}; #define SECS_PER_MIN 60 #define SECS_PER_HOUR (SECS_PER_MIN*60) #define SECS_PER_DAY (24*SECS_PER_HOUR) #define DAYS_PER_YEAR 365 struct tm *gmtime_r(const time_t *timep, struct tm *result) { int i; int Y; int M; int D; int h; int m; int s; D = *timep / SECS_PER_DAY; s = *timep % SECS_PER_DAY; m = s / 60; h = m / 60; m %= 60; s %= 60; /* * Work out the year. We subtract one day for every four years * and every 400 years after 1969. However as leap years don't * occur every 100 years we add one day back to counteract the * the subtraction for every 4 years. */ Y = (D - (1+D/365)/4 + (69+D/365)/100 - (369+D/365)/400)/365; /* * Remember we're doing integer arithmetic here so * leap_years(Y+1970) - leap_years(1970) != leap_years(Y) */ D = D - Y*365 - (leap_years(Y+1970) - leap_years(1970)) + 1; Y += 1970; M = 0; for (i = 0; i < 13; i++) if (D <= days_per_month[is_leap_year(Y) ? 1 : 0][i]) { M = i; break; } D -= days_per_month[is_leap_year(Y)][M-1]; result->tm_year = Y; result->tm_mon = M - 1; result->tm_mday = D; result->tm_hour = h; result->tm_min = m; result->tm_sec = s; return result; } time_t mktime(struct tm *tm) { unsigned long year, month, mday, hour, minute, second, d; static const unsigned long sec_in_400_years = ((3903ul * 365) + (97 * 366)) * 24 * 60 * 60; second = tm->tm_sec; minute = tm->tm_min; hour = tm->tm_hour; mday = tm->tm_mday; month = tm->tm_mon; year = tm->tm_year; /* There are the same number of seconds in any 400-year block; this * limits the iterations in the loop below */ year += 400 * (second / sec_in_400_years); second = second % sec_in_400_years; if (second >= 60) { minute += second / 60; second = second % 60; } if (minute >= 60) { hour += minute / 60; minute = minute % 60; } if (hour >= 24) { mday += hour / 24; hour = hour % 24; } for (d = days_in_month(month, year); mday > d; d = days_in_month(month, year)) { month++; if (month > 11) { month = 0; year++; } mday -= d; } tm->tm_year = year; tm->tm_mon = month; tm->tm_mday = mday; tm->tm_hour = hour; tm->tm_min = minute; tm->tm_sec = second; d = mday; d += days_per_month[is_leap_year(year)][month]; d += (year-1970)*DAYS_PER_YEAR + leap_years(year) - leap_years(1970) - 1; return d*SECS_PER_DAY + hour*SECS_PER_HOUR + minute*SECS_PER_MIN + second; }