1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
#include <stdbool.h>
#include <time.h>
/*
* 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;
}
|