Branch data Line data Source code
1 : : #include <stdbool.h>
2 : : #include <time.h>
3 : :
4 : : /*
5 : : * Returns the number of leap years prior to the given year.
6 : : */
7 : 320 : static int leap_years(int year)
8 : : {
9 : 320 : return (year-1)/4 + (year-1)/400 - (year-1)/100;
10 : : }
11 : :
12 : 765 : static int is_leap_year(int year)
13 : : {
14 : 765 : return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
15 : : }
16 : :
17 : 145 : static int days_in_month(int month, int year)
18 : : {
19 : : static char month_days[] = {
20 : : 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
21 : : };
22 : :
23 : : /* we may need to update this in the year 4000, pending a
24 : : * decision on whether or not it's a leap year */
25 : 145 : if (month == 1)
26 : 15 : return is_leap_year(year) ? 29 : 28;
27 : :
28 : 130 : return month_days[month];
29 : : }
30 : :
31 : : static const int days_per_month[2][13] =
32 : : {{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
33 : : {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
34 : :
35 : : #define SECS_PER_MIN 60
36 : : #define SECS_PER_HOUR (SECS_PER_MIN*60)
37 : : #define SECS_PER_DAY (24*SECS_PER_HOUR)
38 : : #define DAYS_PER_YEAR 365
39 : 75 : struct tm *gmtime_r(const time_t *timep, struct tm *result)
40 : : {
41 : : int i;
42 : : int Y;
43 : : int M;
44 : : int D;
45 : : int h;
46 : : int m;
47 : : int s;
48 : :
49 : 75 : D = *timep / SECS_PER_DAY;
50 : 75 : s = *timep % SECS_PER_DAY;
51 : 75 : m = s / 60;
52 : 75 : h = m / 60;
53 : 75 : m %= 60;
54 : 75 : s %= 60;
55 : :
56 : : /*
57 : : * Work out the year. We subtract one day for every four years
58 : : * and every 400 years after 1969. However as leap years don't
59 : : * occur every 100 years we add one day back to counteract the
60 : : * the subtraction for every 4 years.
61 : : */
62 : 75 : Y = (D - (1+D/365)/4 + (69+D/365)/100 - (369+D/365)/400)/365;
63 : :
64 : : /*
65 : : * Remember we're doing integer arithmetic here so
66 : : * leap_years(Y+1970) - leap_years(1970) != leap_years(Y)
67 : : */
68 : 75 : D = D - Y*365 - (leap_years(Y+1970) - leap_years(1970)) + 1;
69 : 75 : Y += 1970;
70 : :
71 : 75 : M = 0;
72 : 590 : for (i = 0; i < 13; i++)
73 : 590 : if (D <= days_per_month[is_leap_year(Y) ? 1 : 0][i]) {
74 : 75 : M = i;
75 : 75 : break;
76 : : }
77 : :
78 : 75 : D -= days_per_month[is_leap_year(Y)][M-1];
79 : 75 : result->tm_year = Y;
80 : 75 : result->tm_mon = M - 1;
81 : 75 : result->tm_mday = D;
82 : 75 : result->tm_hour = h;
83 : 75 : result->tm_min = m;
84 : 75 : result->tm_sec = s;
85 : 75 : return result;
86 : : }
87 : :
88 : 85 : time_t mktime(struct tm *tm)
89 : : {
90 : : unsigned long year, month, mday, hour, minute, second, d;
91 : : static const unsigned long sec_in_400_years =
92 : : ((3903ul * 365) + (97 * 366)) * 24 * 60 * 60;
93 : :
94 : 85 : second = tm->tm_sec;
95 : 85 : minute = tm->tm_min;
96 : 85 : hour = tm->tm_hour;
97 : 85 : mday = tm->tm_mday;
98 : 85 : month = tm->tm_mon;
99 : 85 : year = tm->tm_year;
100 : :
101 : : /* There are the same number of seconds in any 400-year block; this
102 : : * limits the iterations in the loop below */
103 : 85 : year += 400 * (second / sec_in_400_years);
104 : 85 : second = second % sec_in_400_years;
105 : :
106 : 85 : if (second >= 60) {
107 : 10 : minute += second / 60;
108 : 10 : second = second % 60;
109 : : }
110 : :
111 : 85 : if (minute >= 60) {
112 : 5 : hour += minute / 60;
113 : 5 : minute = minute % 60;
114 : : }
115 : :
116 : 85 : if (hour >= 24) {
117 : 5 : mday += hour / 24;
118 : 5 : hour = hour % 24;
119 : : }
120 : :
121 : 145 : for (d = days_in_month(month, year); mday > d;
122 : 60 : d = days_in_month(month, year)) {
123 : 60 : month++;
124 : 60 : if (month > 11) {
125 : 5 : month = 0;
126 : 5 : year++;
127 : : }
128 : 60 : mday -= d;
129 : : }
130 : :
131 : 85 : tm->tm_year = year;
132 : 85 : tm->tm_mon = month;
133 : 85 : tm->tm_mday = mday;
134 : 85 : tm->tm_hour = hour;
135 : 85 : tm->tm_min = minute;
136 : 85 : tm->tm_sec = second;
137 : :
138 : 85 : d = mday;
139 : 85 : d += days_per_month[is_leap_year(year)][month];
140 : 85 : d += (year-1970)*DAYS_PER_YEAR + leap_years(year) - leap_years(1970) - 1;
141 : 85 : return d*SECS_PER_DAY + hour*SECS_PER_HOUR + minute*SECS_PER_MIN + second;
142 : : }
|