1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apr_portable.h"
18 #include "apr_time.h"
19 #include "apr_lib.h"
20 #include "apr_private.h"
21 #include "apr_strings.h"
22
23 /* private APR headers */
24 #include "apr_arch_internal_time.h"
25
26 /* System Headers required for time library */
27 #if APR_HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30 #if APR_HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef HAVE_TIME_H
34 #include <time.h>
35 #endif
36 /* End System Headers */
37
38 #if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF)
39 static apr_int32_t server_gmt_offset;
40 #define NO_GMTOFF_IN_STRUCT_TM
41 #endif
42
get_offset(struct tm * tm)43 static apr_int32_t get_offset(struct tm *tm)
44 {
45 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
46 return tm->tm_gmtoff;
47 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
48 return tm->__tm_gmtoff;
49 #else
50 #ifdef NETWARE
51 /* Need to adjust the global variable each time otherwise
52 the web server would have to be restarted when daylight
53 savings changes.
54 */
55 if (daylightOnOff) {
56 return server_gmt_offset + daylightOffset;
57 }
58 #else
59 if (tm->tm_isdst)
60 return server_gmt_offset + 3600;
61 #endif
62 return server_gmt_offset;
63 #endif
64 }
65
apr_time_ansi_put(apr_time_t * result,time_t input)66 APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result,
67 time_t input)
68 {
69 *result = (apr_time_t)input * APR_USEC_PER_SEC;
70 return APR_SUCCESS;
71 }
72
73 /* NB NB NB NB This returns GMT!!!!!!!!!! */
apr_time_now(void)74 APR_DECLARE(apr_time_t) apr_time_now(void)
75 {
76 struct timeval tv;
77 gettimeofday(&tv, NULL);
78 return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec;
79 }
80
explode_time(apr_time_exp_t * xt,apr_time_t t,apr_int32_t offset,int use_localtime)81 static void explode_time(apr_time_exp_t *xt, apr_time_t t,
82 apr_int32_t offset, int use_localtime)
83 {
84 struct tm tm;
85 time_t tt = (t / APR_USEC_PER_SEC) + offset;
86 xt->tm_usec = t % APR_USEC_PER_SEC;
87
88 #if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
89 if (use_localtime)
90 localtime_r(&tt, &tm);
91 else
92 gmtime_r(&tt, &tm);
93 #else
94 if (use_localtime)
95 tm = *localtime(&tt);
96 else
97 tm = *gmtime(&tt);
98 #endif
99
100 xt->tm_sec = tm.tm_sec;
101 xt->tm_min = tm.tm_min;
102 xt->tm_hour = tm.tm_hour;
103 xt->tm_mday = tm.tm_mday;
104 xt->tm_mon = tm.tm_mon;
105 xt->tm_year = tm.tm_year;
106 xt->tm_wday = tm.tm_wday;
107 xt->tm_yday = tm.tm_yday;
108 xt->tm_isdst = tm.tm_isdst;
109 xt->tm_gmtoff = get_offset(&tm);
110 }
111
apr_time_exp_tz(apr_time_exp_t * result,apr_time_t input,apr_int32_t offs)112 APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result,
113 apr_time_t input, apr_int32_t offs)
114 {
115 explode_time(result, input, offs, 0);
116 result->tm_gmtoff = offs;
117 return APR_SUCCESS;
118 }
119
apr_time_exp_gmt(apr_time_exp_t * result,apr_time_t input)120 APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result,
121 apr_time_t input)
122 {
123 return apr_time_exp_tz(result, input, 0);
124 }
125
apr_time_exp_lt(apr_time_exp_t * result,apr_time_t input)126 APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result,
127 apr_time_t input)
128 {
129 #if defined(__EMX__)
130 /* EMX gcc (OS/2) has a timezone global we can use */
131 return apr_time_exp_tz(result, input, -timezone);
132 #else
133 explode_time(result, input, 0, 1);
134 return APR_SUCCESS;
135 #endif /* __EMX__ */
136 }
137
apr_time_exp_get(apr_time_t * t,apr_time_exp_t * xt)138 APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt)
139 {
140 apr_time_t year = xt->tm_year;
141 apr_time_t days;
142 static const int dayoffset[12] =
143 {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
144
145 if (xt->tm_mon < 0 || xt->tm_mon >= 12)
146 return APR_EBADDATE;
147
148 /* shift new year to 1st March in order to make leap year calc easy */
149
150 if (xt->tm_mon < 2)
151 year--;
152
153 /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
154
155 days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
156 days += dayoffset[xt->tm_mon] + xt->tm_mday - 1;
157 days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
158 days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec;
159
160 if (days < 0) {
161 return APR_EBADDATE;
162 }
163 *t = days * APR_USEC_PER_SEC + xt->tm_usec;
164 return APR_SUCCESS;
165 }
166
apr_time_exp_gmt_get(apr_time_t * t,apr_time_exp_t * xt)167 APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t,
168 apr_time_exp_t *xt)
169 {
170 apr_status_t status = apr_time_exp_get(t, xt);
171 if (status == APR_SUCCESS)
172 *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC;
173 return status;
174 }
175
apr_os_imp_time_get(apr_os_imp_time_t ** ostime,apr_time_t * aprtime)176 APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime,
177 apr_time_t *aprtime)
178 {
179 (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC;
180 (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC;
181 return APR_SUCCESS;
182 }
183
apr_os_exp_time_get(apr_os_exp_time_t ** ostime,apr_time_exp_t * aprtime)184 APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime,
185 apr_time_exp_t *aprtime)
186 {
187 (*ostime)->tm_sec = aprtime->tm_sec;
188 (*ostime)->tm_min = aprtime->tm_min;
189 (*ostime)->tm_hour = aprtime->tm_hour;
190 (*ostime)->tm_mday = aprtime->tm_mday;
191 (*ostime)->tm_mon = aprtime->tm_mon;
192 (*ostime)->tm_year = aprtime->tm_year;
193 (*ostime)->tm_wday = aprtime->tm_wday;
194 (*ostime)->tm_yday = aprtime->tm_yday;
195 (*ostime)->tm_isdst = aprtime->tm_isdst;
196
197 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
198 (*ostime)->tm_gmtoff = aprtime->tm_gmtoff;
199 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
200 (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff;
201 #endif
202
203 return APR_SUCCESS;
204 }
205
apr_os_imp_time_put(apr_time_t * aprtime,apr_os_imp_time_t ** ostime,apr_pool_t * cont)206 APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime,
207 apr_os_imp_time_t **ostime,
208 apr_pool_t *cont)
209 {
210 *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec;
211 return APR_SUCCESS;
212 }
213
apr_os_exp_time_put(apr_time_exp_t * aprtime,apr_os_exp_time_t ** ostime,apr_pool_t * cont)214 APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime,
215 apr_os_exp_time_t **ostime,
216 apr_pool_t *cont)
217 {
218 aprtime->tm_sec = (*ostime)->tm_sec;
219 aprtime->tm_min = (*ostime)->tm_min;
220 aprtime->tm_hour = (*ostime)->tm_hour;
221 aprtime->tm_mday = (*ostime)->tm_mday;
222 aprtime->tm_mon = (*ostime)->tm_mon;
223 aprtime->tm_year = (*ostime)->tm_year;
224 aprtime->tm_wday = (*ostime)->tm_wday;
225 aprtime->tm_yday = (*ostime)->tm_yday;
226 aprtime->tm_isdst = (*ostime)->tm_isdst;
227
228 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
229 aprtime->tm_gmtoff = (*ostime)->tm_gmtoff;
230 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
231 aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff;
232 #endif
233
234 return APR_SUCCESS;
235 }
236
apr_sleep(apr_interval_time_t t)237 APR_DECLARE(void) apr_sleep(apr_interval_time_t t)
238 {
239 #ifdef OS2
240 DosSleep(t/1000);
241 #elif defined(BEOS)
242 snooze(t);
243 #elif defined(NETWARE)
244 delay(t/1000);
245 #else
246 struct timeval tv;
247 tv.tv_usec = t % APR_USEC_PER_SEC;
248 tv.tv_sec = t / APR_USEC_PER_SEC;
249 select(0, NULL, NULL, NULL, &tv);
250 #endif
251 }
252
253 #ifdef OS2
apr_os2_time_to_apr_time(apr_time_t * result,FDATE os2date,FTIME os2time)254 APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result,
255 FDATE os2date,
256 FTIME os2time)
257 {
258 struct tm tmpdate;
259
260 memset(&tmpdate, 0, sizeof(tmpdate));
261 tmpdate.tm_hour = os2time.hours;
262 tmpdate.tm_min = os2time.minutes;
263 tmpdate.tm_sec = os2time.twosecs * 2;
264
265 tmpdate.tm_mday = os2date.day;
266 tmpdate.tm_mon = os2date.month - 1;
267 tmpdate.tm_year = os2date.year + 80;
268 tmpdate.tm_isdst = -1;
269
270 *result = mktime(&tmpdate) * APR_USEC_PER_SEC;
271 return APR_SUCCESS;
272 }
273
apr_apr_time_to_os2_time(FDATE * os2date,FTIME * os2time,apr_time_t aprtime)274 APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date,
275 FTIME *os2time,
276 apr_time_t aprtime)
277 {
278 time_t ansitime = aprtime / APR_USEC_PER_SEC;
279 struct tm *lt;
280 lt = localtime(&ansitime);
281 os2time->hours = lt->tm_hour;
282 os2time->minutes = lt->tm_min;
283 os2time->twosecs = lt->tm_sec / 2;
284
285 os2date->day = lt->tm_mday;
286 os2date->month = lt->tm_mon + 1;
287 os2date->year = lt->tm_year - 80;
288 return APR_SUCCESS;
289 }
290 #endif
291
292 #ifdef NETWARE
apr_netware_setup_time(void)293 APR_DECLARE(void) apr_netware_setup_time(void)
294 {
295 tzset();
296 server_gmt_offset = -TZONE;
297 }
298 #else
apr_unix_setup_time(void)299 APR_DECLARE(void) apr_unix_setup_time(void)
300 {
301 #ifdef NO_GMTOFF_IN_STRUCT_TM
302 /* Precompute the offset from GMT on systems where it's not
303 in struct tm.
304
305 Note: This offset is normalized to be independent of daylight
306 savings time; if the calculation happens to be done in a
307 time/place where a daylight savings adjustment is in effect,
308 the returned offset has the same value that it would have
309 in the same location if daylight savings were not in effect.
310 The reason for this is that the returned offset can be
311 applied to a past or future timestamp in explode_time(),
312 so the DST adjustment obtained from the current time won't
313 necessarily be applicable.
314
315 mktime() is the inverse of localtime(); so, presumably,
316 passing in a struct tm made by gmtime() let's us calculate
317 the true GMT offset. However, there's a catch: if daylight
318 savings is in effect, gmtime()will set the tm_isdst field
319 and confuse mktime() into returning a time that's offset
320 by one hour. In that case, we must adjust the calculated GMT
321 offset.
322
323 */
324
325 struct timeval now;
326 time_t t1, t2;
327 struct tm t;
328
329 gettimeofday(&now, NULL);
330 t1 = now.tv_sec;
331 t2 = 0;
332
333 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
334 gmtime_r(&t1, &t);
335 #else
336 t = *gmtime(&t1);
337 #endif
338 t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */
339 t2 = mktime(&t);
340 server_gmt_offset = (apr_int32_t) difftime(t1, t2);
341 #endif /* NO_GMTOFF_IN_STRUCT_TM */
342 }
343
344 #endif
345
346 /* A noop on all known Unix implementations */
apr_time_clock_hires(apr_pool_t * p)347 APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p)
348 {
349 return;
350 }
351
352
353