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 /* shift new year to 1st March in order to make leap year calc easy */
146
147 if (xt->tm_mon < 2)
148 year--;
149
150 /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
151
152 days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
153 days += dayoffset[xt->tm_mon] + xt->tm_mday - 1;
154 days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
155 days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec;
156
157 if (days < 0) {
158 return APR_EBADDATE;
159 }
160 *t = days * APR_USEC_PER_SEC + xt->tm_usec;
161 return APR_SUCCESS;
162 }
163
apr_time_exp_gmt_get(apr_time_t * t,apr_time_exp_t * xt)164 APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t,
165 apr_time_exp_t *xt)
166 {
167 apr_status_t status = apr_time_exp_get(t, xt);
168 if (status == APR_SUCCESS)
169 *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC;
170 return status;
171 }
172
apr_os_imp_time_get(apr_os_imp_time_t ** ostime,apr_time_t * aprtime)173 APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime,
174 apr_time_t *aprtime)
175 {
176 (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC;
177 (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC;
178 return APR_SUCCESS;
179 }
180
apr_os_exp_time_get(apr_os_exp_time_t ** ostime,apr_time_exp_t * aprtime)181 APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime,
182 apr_time_exp_t *aprtime)
183 {
184 (*ostime)->tm_sec = aprtime->tm_sec;
185 (*ostime)->tm_min = aprtime->tm_min;
186 (*ostime)->tm_hour = aprtime->tm_hour;
187 (*ostime)->tm_mday = aprtime->tm_mday;
188 (*ostime)->tm_mon = aprtime->tm_mon;
189 (*ostime)->tm_year = aprtime->tm_year;
190 (*ostime)->tm_wday = aprtime->tm_wday;
191 (*ostime)->tm_yday = aprtime->tm_yday;
192 (*ostime)->tm_isdst = aprtime->tm_isdst;
193
194 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
195 (*ostime)->tm_gmtoff = aprtime->tm_gmtoff;
196 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
197 (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff;
198 #endif
199
200 return APR_SUCCESS;
201 }
202
apr_os_imp_time_put(apr_time_t * aprtime,apr_os_imp_time_t ** ostime,apr_pool_t * cont)203 APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime,
204 apr_os_imp_time_t **ostime,
205 apr_pool_t *cont)
206 {
207 *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec;
208 return APR_SUCCESS;
209 }
210
apr_os_exp_time_put(apr_time_exp_t * aprtime,apr_os_exp_time_t ** ostime,apr_pool_t * cont)211 APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime,
212 apr_os_exp_time_t **ostime,
213 apr_pool_t *cont)
214 {
215 aprtime->tm_sec = (*ostime)->tm_sec;
216 aprtime->tm_min = (*ostime)->tm_min;
217 aprtime->tm_hour = (*ostime)->tm_hour;
218 aprtime->tm_mday = (*ostime)->tm_mday;
219 aprtime->tm_mon = (*ostime)->tm_mon;
220 aprtime->tm_year = (*ostime)->tm_year;
221 aprtime->tm_wday = (*ostime)->tm_wday;
222 aprtime->tm_yday = (*ostime)->tm_yday;
223 aprtime->tm_isdst = (*ostime)->tm_isdst;
224
225 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
226 aprtime->tm_gmtoff = (*ostime)->tm_gmtoff;
227 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
228 aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff;
229 #endif
230
231 return APR_SUCCESS;
232 }
233
apr_sleep(apr_interval_time_t t)234 APR_DECLARE(void) apr_sleep(apr_interval_time_t t)
235 {
236 #ifdef OS2
237 DosSleep(t/1000);
238 #elif defined(BEOS)
239 snooze(t);
240 #elif defined(NETWARE)
241 delay(t/1000);
242 #else
243 struct timeval tv;
244 tv.tv_usec = t % APR_USEC_PER_SEC;
245 tv.tv_sec = t / APR_USEC_PER_SEC;
246 select(0, NULL, NULL, NULL, &tv);
247 #endif
248 }
249
250 #ifdef OS2
apr_os2_time_to_apr_time(apr_time_t * result,FDATE os2date,FTIME os2time)251 APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result,
252 FDATE os2date,
253 FTIME os2time)
254 {
255 struct tm tmpdate;
256
257 memset(&tmpdate, 0, sizeof(tmpdate));
258 tmpdate.tm_hour = os2time.hours;
259 tmpdate.tm_min = os2time.minutes;
260 tmpdate.tm_sec = os2time.twosecs * 2;
261
262 tmpdate.tm_mday = os2date.day;
263 tmpdate.tm_mon = os2date.month - 1;
264 tmpdate.tm_year = os2date.year + 80;
265 tmpdate.tm_isdst = -1;
266
267 *result = mktime(&tmpdate) * APR_USEC_PER_SEC;
268 return APR_SUCCESS;
269 }
270
apr_apr_time_to_os2_time(FDATE * os2date,FTIME * os2time,apr_time_t aprtime)271 APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date,
272 FTIME *os2time,
273 apr_time_t aprtime)
274 {
275 time_t ansitime = aprtime / APR_USEC_PER_SEC;
276 struct tm *lt;
277 lt = localtime(&ansitime);
278 os2time->hours = lt->tm_hour;
279 os2time->minutes = lt->tm_min;
280 os2time->twosecs = lt->tm_sec / 2;
281
282 os2date->day = lt->tm_mday;
283 os2date->month = lt->tm_mon + 1;
284 os2date->year = lt->tm_year - 80;
285 return APR_SUCCESS;
286 }
287 #endif
288
289 #ifdef NETWARE
apr_netware_setup_time(void)290 APR_DECLARE(void) apr_netware_setup_time(void)
291 {
292 tzset();
293 server_gmt_offset = -TZONE;
294 }
295 #else
apr_unix_setup_time(void)296 APR_DECLARE(void) apr_unix_setup_time(void)
297 {
298 #ifdef NO_GMTOFF_IN_STRUCT_TM
299 /* Precompute the offset from GMT on systems where it's not
300 in struct tm.
301
302 Note: This offset is normalized to be independent of daylight
303 savings time; if the calculation happens to be done in a
304 time/place where a daylight savings adjustment is in effect,
305 the returned offset has the same value that it would have
306 in the same location if daylight savings were not in effect.
307 The reason for this is that the returned offset can be
308 applied to a past or future timestamp in explode_time(),
309 so the DST adjustment obtained from the current time won't
310 necessarily be applicable.
311
312 mktime() is the inverse of localtime(); so, presumably,
313 passing in a struct tm made by gmtime() let's us calculate
314 the true GMT offset. However, there's a catch: if daylight
315 savings is in effect, gmtime()will set the tm_isdst field
316 and confuse mktime() into returning a time that's offset
317 by one hour. In that case, we must adjust the calculated GMT
318 offset.
319
320 */
321
322 struct timeval now;
323 time_t t1, t2;
324 struct tm t;
325
326 gettimeofday(&now, NULL);
327 t1 = now.tv_sec;
328 t2 = 0;
329
330 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
331 gmtime_r(&t1, &t);
332 #else
333 t = *gmtime(&t1);
334 #endif
335 t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */
336 t2 = mktime(&t);
337 server_gmt_offset = (apr_int32_t) difftime(t1, t2);
338 #endif /* NO_GMTOFF_IN_STRUCT_TM */
339 }
340
341 #endif
342
343 /* A noop on all known Unix implementations */
apr_time_clock_hires(apr_pool_t * p)344 APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p)
345 {
346 return;
347 }
348
349
350