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