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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "apr_portable.h"
20 #include "apr_private.h"
21 #include "apr_strings.h"
23 /* private APR headers */
24 #include "apr_arch_internal_time.h"
26 /* System Headers required for time library */
27 #if APR_HAVE_SYS_TIME_H
36 /* End System Headers */
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
43 static apr_int32_t get_offset(struct tm *tm)
45 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
47 #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
48 return tm->__tm_gmtoff;
51 /* Need to adjust the global variable each time otherwise
52 the web server would have to be restarted when daylight
56 return server_gmt_offset + daylightOffset;
60 return server_gmt_offset + 3600;
62 return server_gmt_offset;
66 APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result,
69 *result = (apr_time_t)input * APR_USEC_PER_SEC;
73 /* NB NB NB NB This returns GMT!!!!!!!!!! */
74 APR_DECLARE(apr_time_t) apr_time_now(void)
77 gettimeofday(&tv, NULL);
78 return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec;
81 static void explode_time(apr_time_exp_t *xt, apr_time_t t,
82 apr_int32_t offset, int use_localtime)
85 time_t tt = (t / APR_USEC_PER_SEC) + offset;
86 xt->tm_usec = t % APR_USEC_PER_SEC;
88 #if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
90 localtime_r(&tt, &tm);
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);
112 APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result,
113 apr_time_t input, apr_int32_t offs)
115 explode_time(result, input, offs, 0);
116 result->tm_gmtoff = offs;
120 APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result,
123 return apr_time_exp_tz(result, input, 0);
126 APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result,
130 /* EMX gcc (OS/2) has a timezone global we can use */
131 return apr_time_exp_tz(result, input, -timezone);
133 explode_time(result, input, 0, 1);
138 APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt)
140 apr_time_t year = xt->tm_year;
142 static const int dayoffset[12] =
143 {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
145 /* shift new year to 1st March in order to make leap year calc easy */
150 /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
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;
160 *t = days * APR_USEC_PER_SEC + xt->tm_usec;
164 APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t,
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;
173 APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime,
176 (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC;
177 (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC;
181 APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime,
182 apr_time_exp_t *aprtime)
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;
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;
203 APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime,
204 apr_os_imp_time_t **ostime,
207 *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec;
211 APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime,
212 apr_os_exp_time_t **ostime,
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;
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;
234 APR_DECLARE(void) apr_sleep(apr_interval_time_t t)
240 #elif defined(NETWARE)
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);
251 APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result,
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;
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;
267 *result = mktime(&tmpdate) * APR_USEC_PER_SEC;
271 APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date,
275 time_t ansitime = aprtime / APR_USEC_PER_SEC;
277 lt = localtime(&ansitime);
278 os2time->hours = lt->tm_hour;
279 os2time->minutes = lt->tm_min;
280 os2time->twosecs = lt->tm_sec / 2;
282 os2date->day = lt->tm_mday;
283 os2date->month = lt->tm_mon + 1;
284 os2date->year = lt->tm_year - 80;
290 APR_DECLARE(void) apr_netware_setup_time(void)
293 server_gmt_offset = -TZONE;
296 APR_DECLARE(void) apr_unix_setup_time(void)
298 #ifdef NO_GMTOFF_IN_STRUCT_TM
299 /* Precompute the offset from GMT on systems where it's not
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.
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
326 gettimeofday(&now, NULL);
330 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
335 t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */
337 server_gmt_offset = (apr_int32_t) difftime(t1, t2);
338 #endif /* NO_GMTOFF_IN_STRUCT_TM */
343 /* A noop on all known Unix implementations */
344 APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p)