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) 39static apr_int32_t server_gmt_offset; 40#define NO_GMTOFF_IN_STRUCT_TM 41#endif 42 43static 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 66APR_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!!!!!!!!!! */ 74APR_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 81static 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 112APR_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 120APR_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 126APR_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 138APR_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 164APR_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 173APR_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 181APR_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 203APR_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 211APR_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 234APR_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 251APR_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 271APR_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 290APR_DECLARE(void) apr_netware_setup_time(void) 291{ 292 tzset(); 293 server_gmt_offset = -TZONE; 294} 295#else 296APR_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 */ 344APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) 345{ 346 return; 347} 348 349 350