Rev 4874 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * mktime.c |
||
3 | * Original Author: G. Haley |
||
4 | * |
||
5 | * Converts the broken-down time, expressed as local time, in the structure |
||
6 | * pointed to by tim_p into a calendar time value. The original values of the |
||
7 | * tm_wday and tm_yday fields of the structure are ignored, and the original |
||
8 | * values of the other fields have no restrictions. On successful completion |
||
9 | * the fields of the structure are set to represent the specified calendar |
||
10 | * time. Returns the specified calendar time. If the calendar time can not be |
||
11 | * represented, returns the value (time_t) -1. |
||
12 | * |
||
13 | * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland. |
||
14 | */ |
||
15 | |||
16 | /* |
||
17 | FUNCTION |
||
18 | < |
||
19 | |||
20 | INDEX |
||
21 | mktime |
||
22 | |||
23 | ANSI_SYNOPSIS |
||
24 | #include |
||
25 | time_t mktime(struct tm *<[timp]>); |
||
26 | |||
27 | TRAD_SYNOPSIS |
||
28 | #include |
||
29 | time_t mktime(<[timp]>) |
||
30 | struct tm *<[timp]>; |
||
31 | |||
32 | DESCRIPTION |
||
33 | < |
||
34 | its representation from the traditional representation defined by |
||
35 | < |
||
36 | |||
37 | < |
||
38 | |||
39 | RETURNS |
||
40 | If the contents of the structure at <[timp]> do not form a valid |
||
41 | calendar time representation, the result is <<-1>>. Otherwise, the |
||
42 | result is the time, converted to a < |
||
43 | |||
44 | PORTABILITY |
||
45 | ANSI C requires < |
||
46 | |||
47 | < |
||
48 | */ |
||
49 | |||
50 | #include |
||
51 | #include |
||
52 | #include "local.h" |
||
53 | |||
54 | #define _SEC_IN_MINUTE 60L |
||
55 | #define _SEC_IN_HOUR 3600L |
||
56 | #define _SEC_IN_DAY 86400L |
||
57 | |||
58 | static _CONST int DAYS_IN_MONTH[12] = |
||
59 | {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
||
60 | |||
61 | #define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x]) |
||
62 | |||
63 | static _CONST int _DAYS_BEFORE_MONTH[12] = |
||
64 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; |
||
65 | |||
66 | #define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0)) |
||
67 | #define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365) |
||
68 | |||
69 | static void |
||
70 | _DEFUN(validate_structure, (tim_p), |
||
71 | struct tm *tim_p) |
||
72 | { |
||
73 | div_t res; |
||
74 | int days_in_feb = 28; |
||
75 | |||
76 | /* calculate time & date to account for out of range values */ |
||
77 | if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59) |
||
78 | { |
||
79 | res = div (tim_p->tm_sec, 60); |
||
80 | tim_p->tm_min += res.quot; |
||
81 | if ((tim_p->tm_sec = res.rem) < 0) |
||
82 | { |
||
83 | tim_p->tm_sec += 60; |
||
84 | --tim_p->tm_min; |
||
85 | } |
||
86 | } |
||
87 | |||
88 | if (tim_p->tm_min < 0 || tim_p->tm_min > 59) |
||
89 | { |
||
90 | res = div (tim_p->tm_min, 60); |
||
91 | tim_p->tm_hour += res.quot; |
||
92 | if ((tim_p->tm_min = res.rem) < 0) |
||
93 | { |
||
94 | tim_p->tm_min += 60; |
||
95 | --tim_p->tm_hour; |
||
96 | } |
||
97 | } |
||
98 | |||
99 | if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23) |
||
100 | { |
||
101 | res = div (tim_p->tm_hour, 24); |
||
102 | tim_p->tm_mday += res.quot; |
||
103 | if ((tim_p->tm_hour = res.rem) < 0) |
||
104 | { |
||
105 | tim_p->tm_hour += 24; |
||
106 | --tim_p->tm_mday; |
||
107 | } |
||
108 | } |
||
109 | |||
110 | if (tim_p->tm_mon < 0 || tim_p->tm_mon > 11) |
||
111 | { |
||
112 | res = div (tim_p->tm_mon, 12); |
||
113 | tim_p->tm_year += res.quot; |
||
114 | if ((tim_p->tm_mon = res.rem) < 0) |
||
115 | { |
||
116 | tim_p->tm_mon += 12; |
||
117 | --tim_p->tm_year; |
||
118 | } |
||
119 | } |
||
120 | |||
121 | if (_DAYS_IN_YEAR (tim_p->tm_year) == 366) |
||
122 | days_in_feb = 29; |
||
123 | |||
124 | if (tim_p->tm_mday <= 0) |
||
125 | { |
||
126 | while (tim_p->tm_mday <= 0) |
||
127 | { |
||
128 | if (--tim_p->tm_mon == -1) |
||
129 | { |
||
130 | tim_p->tm_year--; |
||
131 | tim_p->tm_mon = 11; |
||
132 | days_in_feb = |
||
133 | ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? |
||
134 | 29 : 28); |
||
135 | } |
||
136 | tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon); |
||
137 | } |
||
138 | } |
||
139 | else |
||
140 | { |
||
141 | while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon)) |
||
142 | { |
||
143 | tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon); |
||
144 | if (++tim_p->tm_mon == 12) |
||
145 | { |
||
146 | tim_p->tm_year++; |
||
147 | tim_p->tm_mon = 0; |
||
148 | days_in_feb = |
||
149 | ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? |
||
150 | 29 : 28); |
||
151 | } |
||
152 | } |
||
153 | } |
||
154 | } |
||
155 | |||
156 | time_t |
||
157 | _DEFUN(mktime, (tim_p), |
||
158 | struct tm *tim_p) |
||
159 | { |
||
160 | time_t tim = 0; |
||
161 | long days = 0; |
||
162 | int year, isdst=0; |
||
163 | __tzinfo_type *tz = __gettzinfo (); |
||
164 | |||
165 | /* validate structure */ |
||
166 | validate_structure (tim_p); |
||
167 | |||
168 | /* compute hours, minutes, seconds */ |
||
169 | tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) + |
||
170 | (tim_p->tm_hour * _SEC_IN_HOUR); |
||
171 | |||
172 | /* compute days in year */ |
||
173 | days += tim_p->tm_mday - 1; |
||
174 | days += _DAYS_BEFORE_MONTH[tim_p->tm_mon]; |
||
175 | if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366) |
||
176 | days++; |
||
177 | |||
178 | /* compute day of the year */ |
||
179 | tim_p->tm_yday = days; |
||
180 | |||
181 | if (tim_p->tm_year > 10000 || tim_p->tm_year < -10000) |
||
182 | return (time_t) -1; |
||
183 | |||
184 | /* compute days in other years */ |
||
185 | if ((year = tim_p->tm_year) > 70) |
||
186 | { |
||
187 | for (year = 70; year < tim_p->tm_year; year++) |
||
188 | days += _DAYS_IN_YEAR (year); |
||
189 | } |
||
190 | else if (year < 70) |
||
191 | { |
||
192 | for (year = 69; year > tim_p->tm_year; year--) |
||
193 | days -= _DAYS_IN_YEAR (year); |
||
194 | days -= _DAYS_IN_YEAR (year); |
||
195 | } |
||
196 | |||
197 | /* compute total seconds */ |
||
198 | tim += (days * _SEC_IN_DAY); |
||
199 | |||
200 | TZ_LOCK; |
||
201 | |||
6099 | serge | 202 | _tzset_unlocked (); |
203 | |||
4349 | Serge | 204 | if (_daylight) |
205 | { |
||
206 | int tm_isdst; |
||
207 | int y = tim_p->tm_year + YEAR_BASE; |
||
6099 | serge | 208 | /* Convert user positive into 1 */ |
209 | tm_isdst = tim_p->tm_isdst > 0 ? 1 : tim_p->tm_isdst; |
||
210 | isdst = tm_isdst; |
||
4349 | Serge | 211 | |
212 | if (y == tz->__tzyear || __tzcalc_limits (y)) |
||
213 | { |
||
214 | /* calculate start of dst in dst local time and |
||
215 | start of std in both std local time and dst local time */ |
||
216 | time_t startdst_dst = tz->__tzrule[0].change |
||
217 | - (time_t) tz->__tzrule[1].offset; |
||
218 | time_t startstd_dst = tz->__tzrule[1].change |
||
219 | - (time_t) tz->__tzrule[1].offset; |
||
220 | time_t startstd_std = tz->__tzrule[1].change |
||
221 | - (time_t) tz->__tzrule[0].offset; |
||
222 | /* if the time is in the overlap between dst and std local times */ |
||
223 | if (tim >= startstd_std && tim < startstd_dst) |
||
224 | ; /* we let user decide or leave as -1 */ |
||
225 | else |
||
226 | { |
||
227 | isdst = (tz->__tznorth |
||
228 | ? (tim >= startdst_dst && tim < startstd_std) |
||
229 | : (tim >= startdst_dst || tim < startstd_std)); |
||
230 | /* if user committed and was wrong, perform correction, but not |
||
231 | * if the user has given a negative value (which |
||
232 | * asks mktime() to determine if DST is in effect or not) */ |
||
233 | if (tm_isdst >= 0 && (isdst ^ tm_isdst) == 1) |
||
234 | { |
||
235 | /* we either subtract or add the difference between |
||
236 | time zone offsets, depending on which way the user got it |
||
237 | wrong. The diff is typically one hour, or 3600 seconds, |
||
238 | and should fit in a 16-bit int, even though offset |
||
239 | is a long to accomodate 12 hours. */ |
||
240 | int diff = (int) (tz->__tzrule[0].offset |
||
241 | - tz->__tzrule[1].offset); |
||
242 | if (!isdst) |
||
243 | diff = -diff; |
||
244 | tim_p->tm_sec += diff; |
||
245 | tim += diff; /* we also need to correct our current time calculation */ |
||
246 | int mday = tim_p->tm_mday; |
||
247 | validate_structure (tim_p); |
||
248 | mday = tim_p->tm_mday - mday; |
||
249 | /* roll over occurred */ |
||
250 | if (mday) { |
||
251 | /* compensate for month roll overs */ |
||
252 | if (mday > 1) |
||
253 | mday = -1; |
||
254 | else if (mday < -1) |
||
255 | mday = 1; |
||
256 | /* update days for wday calculation */ |
||
257 | days += mday; |
||
258 | /* handle yday */ |
||
259 | if ((tim_p->tm_yday += mday) < 0) { |
||
260 | --year; |
||
261 | tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1; |
||
262 | } else { |
||
263 | mday = _DAYS_IN_YEAR(year); |
||
264 | if (tim_p->tm_yday > (mday - 1)) |
||
265 | tim_p->tm_yday -= mday; |
||
266 | } |
||
267 | } |
||
268 | } |
||
269 | } |
||
270 | } |
||
271 | } |
||
272 | |||
273 | /* add appropriate offset to put time in gmt format */ |
||
274 | if (isdst == 1) |
||
275 | tim += (time_t) tz->__tzrule[1].offset; |
||
276 | else /* otherwise assume std time */ |
||
277 | tim += (time_t) tz->__tzrule[0].offset; |
||
278 | |||
279 | TZ_UNLOCK; |
||
280 | |||
281 | /* reset isdst flag to what we have calculated */ |
||
282 | tim_p->tm_isdst = isdst; |
||
283 | |||
284 | /* compute day of the week */ |
||
285 | if ((tim_p->tm_wday = (days + 4) % 7) < 0) |
||
286 | tim_p->tm_wday += 7; |
||
287 | |||
288 | return tim; |
||
289 | }>>>>>>>>>=>=>>>>>>>>> |