1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_portable.h"
18251875Speter#include "apr_time.h"
19251875Speter#include "apr_lib.h"
20251875Speter#include "apr_private.h"
21251875Speter#include "apr_strings.h"
22251875Speter
23251875Speter/* private APR headers */
24251875Speter#include "apr_arch_internal_time.h"
25251875Speter
26251875Speter/* System Headers required for time library */
27251875Speter#if APR_HAVE_SYS_TIME_H
28251875Speter#include <sys/time.h>
29251875Speter#endif
30251875Speter#if APR_HAVE_UNISTD_H
31251875Speter#include <unistd.h>
32251875Speter#endif
33251875Speter#ifdef HAVE_TIME_H
34251875Speter#include <time.h>
35251875Speter#endif
36251875Speter/* End System Headers */
37251875Speter
38251875Speter#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF)
39251875Speterstatic apr_int32_t server_gmt_offset;
40251875Speter#define NO_GMTOFF_IN_STRUCT_TM
41251875Speter#endif
42251875Speter
43251875Speterstatic apr_int32_t get_offset(struct tm *tm)
44251875Speter{
45251875Speter#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
46251875Speter    return tm->tm_gmtoff;
47251875Speter#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
48251875Speter    return tm->__tm_gmtoff;
49251875Speter#else
50251875Speter#ifdef NETWARE
51251875Speter    /* Need to adjust the global variable each time otherwise
52251875Speter        the web server would have to be restarted when daylight
53251875Speter        savings changes.
54251875Speter    */
55251875Speter    if (daylightOnOff) {
56251875Speter        return server_gmt_offset + daylightOffset;
57251875Speter    }
58251875Speter#else
59251875Speter    if (tm->tm_isdst)
60251875Speter        return server_gmt_offset + 3600;
61251875Speter#endif
62251875Speter    return server_gmt_offset;
63251875Speter#endif
64251875Speter}
65251875Speter
66251875SpeterAPR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result,
67251875Speter                                            time_t input)
68251875Speter{
69251875Speter    *result = (apr_time_t)input * APR_USEC_PER_SEC;
70251875Speter    return APR_SUCCESS;
71251875Speter}
72251875Speter
73251875Speter/* NB NB NB NB This returns GMT!!!!!!!!!! */
74251875SpeterAPR_DECLARE(apr_time_t) apr_time_now(void)
75251875Speter{
76251875Speter    struct timeval tv;
77251875Speter    gettimeofday(&tv, NULL);
78251875Speter    return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec;
79251875Speter}
80251875Speter
81251875Speterstatic void explode_time(apr_time_exp_t *xt, apr_time_t t,
82251875Speter                         apr_int32_t offset, int use_localtime)
83251875Speter{
84251875Speter    struct tm tm;
85251875Speter    time_t tt = (t / APR_USEC_PER_SEC) + offset;
86251875Speter    xt->tm_usec = t % APR_USEC_PER_SEC;
87251875Speter
88251875Speter#if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
89251875Speter    if (use_localtime)
90251875Speter        localtime_r(&tt, &tm);
91251875Speter    else
92251875Speter        gmtime_r(&tt, &tm);
93251875Speter#else
94251875Speter    if (use_localtime)
95251875Speter        tm = *localtime(&tt);
96251875Speter    else
97251875Speter        tm = *gmtime(&tt);
98251875Speter#endif
99251875Speter
100251875Speter    xt->tm_sec  = tm.tm_sec;
101251875Speter    xt->tm_min  = tm.tm_min;
102251875Speter    xt->tm_hour = tm.tm_hour;
103251875Speter    xt->tm_mday = tm.tm_mday;
104251875Speter    xt->tm_mon  = tm.tm_mon;
105251875Speter    xt->tm_year = tm.tm_year;
106251875Speter    xt->tm_wday = tm.tm_wday;
107251875Speter    xt->tm_yday = tm.tm_yday;
108251875Speter    xt->tm_isdst = tm.tm_isdst;
109251875Speter    xt->tm_gmtoff = get_offset(&tm);
110251875Speter}
111251875Speter
112251875SpeterAPR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result,
113251875Speter                                          apr_time_t input, apr_int32_t offs)
114251875Speter{
115251875Speter    explode_time(result, input, offs, 0);
116251875Speter    result->tm_gmtoff = offs;
117251875Speter    return APR_SUCCESS;
118251875Speter}
119251875Speter
120251875SpeterAPR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result,
121251875Speter                                           apr_time_t input)
122251875Speter{
123251875Speter    return apr_time_exp_tz(result, input, 0);
124251875Speter}
125251875Speter
126251875SpeterAPR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result,
127251875Speter                                                apr_time_t input)
128251875Speter{
129251875Speter#if defined(__EMX__)
130251875Speter    /* EMX gcc (OS/2) has a timezone global we can use */
131251875Speter    return apr_time_exp_tz(result, input, -timezone);
132251875Speter#else
133251875Speter    explode_time(result, input, 0, 1);
134251875Speter    return APR_SUCCESS;
135251875Speter#endif /* __EMX__ */
136251875Speter}
137251875Speter
138251875SpeterAPR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt)
139251875Speter{
140251875Speter    apr_time_t year = xt->tm_year;
141251875Speter    apr_time_t days;
142251875Speter    static const int dayoffset[12] =
143251875Speter    {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
144251875Speter
145251875Speter    /* shift new year to 1st March in order to make leap year calc easy */
146251875Speter
147251875Speter    if (xt->tm_mon < 2)
148251875Speter        year--;
149251875Speter
150251875Speter    /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
151251875Speter
152251875Speter    days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
153251875Speter    days += dayoffset[xt->tm_mon] + xt->tm_mday - 1;
154251875Speter    days -= 25508;              /* 1 jan 1970 is 25508 days since 1 mar 1900 */
155251875Speter    days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec;
156251875Speter
157251875Speter    if (days < 0) {
158251875Speter        return APR_EBADDATE;
159251875Speter    }
160251875Speter    *t = days * APR_USEC_PER_SEC + xt->tm_usec;
161251875Speter    return APR_SUCCESS;
162251875Speter}
163251875Speter
164251875SpeterAPR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t,
165251875Speter                                               apr_time_exp_t *xt)
166251875Speter{
167251875Speter    apr_status_t status = apr_time_exp_get(t, xt);
168251875Speter    if (status == APR_SUCCESS)
169251875Speter        *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC;
170251875Speter    return status;
171251875Speter}
172251875Speter
173251875SpeterAPR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime,
174251875Speter                                              apr_time_t *aprtime)
175251875Speter{
176251875Speter    (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC;
177251875Speter    (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC;
178251875Speter    return APR_SUCCESS;
179251875Speter}
180251875Speter
181251875SpeterAPR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime,
182251875Speter                                              apr_time_exp_t *aprtime)
183251875Speter{
184251875Speter    (*ostime)->tm_sec  = aprtime->tm_sec;
185251875Speter    (*ostime)->tm_min  = aprtime->tm_min;
186251875Speter    (*ostime)->tm_hour = aprtime->tm_hour;
187251875Speter    (*ostime)->tm_mday = aprtime->tm_mday;
188251875Speter    (*ostime)->tm_mon  = aprtime->tm_mon;
189251875Speter    (*ostime)->tm_year = aprtime->tm_year;
190251875Speter    (*ostime)->tm_wday = aprtime->tm_wday;
191251875Speter    (*ostime)->tm_yday = aprtime->tm_yday;
192251875Speter    (*ostime)->tm_isdst = aprtime->tm_isdst;
193251875Speter
194251875Speter#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
195251875Speter    (*ostime)->tm_gmtoff = aprtime->tm_gmtoff;
196251875Speter#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
197251875Speter    (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff;
198251875Speter#endif
199251875Speter
200251875Speter    return APR_SUCCESS;
201251875Speter}
202251875Speter
203251875SpeterAPR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime,
204251875Speter                                              apr_os_imp_time_t **ostime,
205251875Speter                                              apr_pool_t *cont)
206251875Speter{
207251875Speter    *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec;
208251875Speter    return APR_SUCCESS;
209251875Speter}
210251875Speter
211251875SpeterAPR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime,
212251875Speter                                              apr_os_exp_time_t **ostime,
213251875Speter                                              apr_pool_t *cont)
214251875Speter{
215251875Speter    aprtime->tm_sec = (*ostime)->tm_sec;
216251875Speter    aprtime->tm_min = (*ostime)->tm_min;
217251875Speter    aprtime->tm_hour = (*ostime)->tm_hour;
218251875Speter    aprtime->tm_mday = (*ostime)->tm_mday;
219251875Speter    aprtime->tm_mon = (*ostime)->tm_mon;
220251875Speter    aprtime->tm_year = (*ostime)->tm_year;
221251875Speter    aprtime->tm_wday = (*ostime)->tm_wday;
222251875Speter    aprtime->tm_yday = (*ostime)->tm_yday;
223251875Speter    aprtime->tm_isdst = (*ostime)->tm_isdst;
224251875Speter
225251875Speter#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
226251875Speter    aprtime->tm_gmtoff = (*ostime)->tm_gmtoff;
227251875Speter#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
228251875Speter    aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff;
229251875Speter#endif
230251875Speter
231251875Speter    return APR_SUCCESS;
232251875Speter}
233251875Speter
234251875SpeterAPR_DECLARE(void) apr_sleep(apr_interval_time_t t)
235251875Speter{
236251875Speter#ifdef OS2
237251875Speter    DosSleep(t/1000);
238251875Speter#elif defined(BEOS)
239251875Speter    snooze(t);
240251875Speter#elif defined(NETWARE)
241251875Speter    delay(t/1000);
242251875Speter#else
243251875Speter    struct timeval tv;
244251875Speter    tv.tv_usec = t % APR_USEC_PER_SEC;
245251875Speter    tv.tv_sec = t / APR_USEC_PER_SEC;
246251875Speter    select(0, NULL, NULL, NULL, &tv);
247251875Speter#endif
248251875Speter}
249251875Speter
250251875Speter#ifdef OS2
251251875SpeterAPR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result,
252251875Speter                                                   FDATE os2date,
253251875Speter                                                   FTIME os2time)
254251875Speter{
255251875Speter  struct tm tmpdate;
256251875Speter
257251875Speter  memset(&tmpdate, 0, sizeof(tmpdate));
258251875Speter  tmpdate.tm_hour  = os2time.hours;
259251875Speter  tmpdate.tm_min   = os2time.minutes;
260251875Speter  tmpdate.tm_sec   = os2time.twosecs * 2;
261251875Speter
262251875Speter  tmpdate.tm_mday  = os2date.day;
263251875Speter  tmpdate.tm_mon   = os2date.month - 1;
264251875Speter  tmpdate.tm_year  = os2date.year + 80;
265251875Speter  tmpdate.tm_isdst = -1;
266251875Speter
267251875Speter  *result = mktime(&tmpdate) * APR_USEC_PER_SEC;
268251875Speter  return APR_SUCCESS;
269251875Speter}
270251875Speter
271251875SpeterAPR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date,
272251875Speter                                                   FTIME *os2time,
273251875Speter                                                   apr_time_t aprtime)
274251875Speter{
275251875Speter    time_t ansitime = aprtime / APR_USEC_PER_SEC;
276251875Speter    struct tm *lt;
277251875Speter    lt = localtime(&ansitime);
278251875Speter    os2time->hours    = lt->tm_hour;
279251875Speter    os2time->minutes  = lt->tm_min;
280251875Speter    os2time->twosecs  = lt->tm_sec / 2;
281251875Speter
282251875Speter    os2date->day      = lt->tm_mday;
283251875Speter    os2date->month    = lt->tm_mon + 1;
284251875Speter    os2date->year     = lt->tm_year - 80;
285251875Speter    return APR_SUCCESS;
286251875Speter}
287251875Speter#endif
288251875Speter
289251875Speter#ifdef NETWARE
290251875SpeterAPR_DECLARE(void) apr_netware_setup_time(void)
291251875Speter{
292251875Speter    tzset();
293251875Speter    server_gmt_offset = -TZONE;
294251875Speter}
295251875Speter#else
296251875SpeterAPR_DECLARE(void) apr_unix_setup_time(void)
297251875Speter{
298251875Speter#ifdef NO_GMTOFF_IN_STRUCT_TM
299251875Speter    /* Precompute the offset from GMT on systems where it's not
300251875Speter       in struct tm.
301251875Speter
302251875Speter       Note: This offset is normalized to be independent of daylight
303251875Speter       savings time; if the calculation happens to be done in a
304251875Speter       time/place where a daylight savings adjustment is in effect,
305251875Speter       the returned offset has the same value that it would have
306251875Speter       in the same location if daylight savings were not in effect.
307251875Speter       The reason for this is that the returned offset can be
308251875Speter       applied to a past or future timestamp in explode_time(),
309251875Speter       so the DST adjustment obtained from the current time won't
310251875Speter       necessarily be applicable.
311251875Speter
312251875Speter       mktime() is the inverse of localtime(); so, presumably,
313251875Speter       passing in a struct tm made by gmtime() let's us calculate
314251875Speter       the true GMT offset. However, there's a catch: if daylight
315251875Speter       savings is in effect, gmtime()will set the tm_isdst field
316251875Speter       and confuse mktime() into returning a time that's offset
317251875Speter       by one hour. In that case, we must adjust the calculated GMT
318251875Speter       offset.
319251875Speter
320251875Speter     */
321251875Speter
322251875Speter    struct timeval now;
323251875Speter    time_t t1, t2;
324251875Speter    struct tm t;
325251875Speter
326251875Speter    gettimeofday(&now, NULL);
327251875Speter    t1 = now.tv_sec;
328251875Speter    t2 = 0;
329251875Speter
330251875Speter#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
331251875Speter    gmtime_r(&t1, &t);
332251875Speter#else
333251875Speter    t = *gmtime(&t1);
334251875Speter#endif
335251875Speter    t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */
336251875Speter    t2 = mktime(&t);
337251875Speter    server_gmt_offset = (apr_int32_t) difftime(t1, t2);
338251875Speter#endif /* NO_GMTOFF_IN_STRUCT_TM */
339251875Speter}
340251875Speter
341251875Speter#endif
342251875Speter
343251875Speter/* A noop on all known Unix implementations */
344251875SpeterAPR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p)
345251875Speter{
346251875Speter    return;
347251875Speter}
348251875Speter
349251875Speter
350