1 /* $NetBSD: time.c,v 1.6 2014/12/10 04:38:01 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2006-2009, 2012-2014 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp */ 21 22 #include <config.h> 23 24 #include <errno.h> 25 #include <limits.h> 26 #include <stddef.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <time.h> 30 31 #include <windows.h> 32 33 #include <isc/assertions.h> 34 #include <isc/time.h> 35 #include <isc/tm.h> 36 #include <isc/util.h> 37 38 /* 39 * struct FILETIME uses "100-nanoseconds intervals". 40 * NS / S = 1000000000 (10^9). 41 * While it is reasonably obvious that this makes the needed 42 * conversion factor 10^7, it is coded this way for additional clarity. 43 */ 44 #define NS_PER_S 1000000000 45 #define NS_INTERVAL 100 46 #define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) 47 #define UINT64_MAX _UI64_MAX 48 49 /*** 50 *** Absolute Times 51 ***/ 52 53 static const isc_time_t epoch = { { 0, 0 } }; 54 LIBISC_EXTERNAL_DATA const isc_time_t * const isc_time_epoch = &epoch; 55 56 /*** 57 *** Intervals 58 ***/ 59 60 static const isc_interval_t zero_interval = { 0 }; 61 LIBISC_EXTERNAL_DATA const isc_interval_t * const isc_interval_zero = &zero_interval; 62 63 void 64 isc_interval_set(isc_interval_t *i, unsigned int seconds, 65 unsigned int nanoseconds) 66 { 67 REQUIRE(i != NULL); 68 REQUIRE(nanoseconds < NS_PER_S); 69 70 /* 71 * This rounds nanoseconds up not down. 72 */ 73 i->interval = (LONGLONG)seconds * INTERVALS_PER_S 74 + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; 75 } 76 77 isc_boolean_t 78 isc_interval_iszero(const isc_interval_t *i) { 79 REQUIRE(i != NULL); 80 if (i->interval == 0) 81 return (ISC_TRUE); 82 83 return (ISC_FALSE); 84 } 85 86 void 87 isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { 88 SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 89 FILETIME temp; 90 ULARGE_INTEGER i1; 91 92 REQUIRE(t != NULL); 93 REQUIRE(nanoseconds < NS_PER_S); 94 95 SystemTimeToFileTime(&epoch, &temp); 96 97 i1.LowPart = temp.dwLowDateTime; 98 i1.HighPart = temp.dwHighDateTime; 99 100 i1.QuadPart += (unsigned __int64)nanoseconds/100; 101 i1.QuadPart += (unsigned __int64)seconds*10000000; 102 103 t->absolute.dwLowDateTime = i1.LowPart; 104 t->absolute.dwHighDateTime = i1.HighPart; 105 } 106 107 void 108 isc_time_settoepoch(isc_time_t *t) { 109 REQUIRE(t != NULL); 110 111 t->absolute.dwLowDateTime = 0; 112 t->absolute.dwHighDateTime = 0; 113 } 114 115 isc_boolean_t 116 isc_time_isepoch(const isc_time_t *t) { 117 REQUIRE(t != NULL); 118 119 if (t->absolute.dwLowDateTime == 0 && 120 t->absolute.dwHighDateTime == 0) 121 return (ISC_TRUE); 122 123 return (ISC_FALSE); 124 } 125 126 isc_result_t 127 isc_time_now(isc_time_t *t) { 128 REQUIRE(t != NULL); 129 130 GetSystemTimeAsFileTime(&t->absolute); 131 132 return (ISC_R_SUCCESS); 133 } 134 135 isc_result_t 136 isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { 137 ULARGE_INTEGER i1; 138 139 REQUIRE(t != NULL); 140 REQUIRE(i != NULL); 141 142 GetSystemTimeAsFileTime(&t->absolute); 143 144 i1.LowPart = t->absolute.dwLowDateTime; 145 i1.HighPart = t->absolute.dwHighDateTime; 146 147 if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 148 return (ISC_R_RANGE); 149 150 i1.QuadPart += i->interval; 151 152 t->absolute.dwLowDateTime = i1.LowPart; 153 t->absolute.dwHighDateTime = i1.HighPart; 154 155 return (ISC_R_SUCCESS); 156 } 157 158 int 159 isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { 160 REQUIRE(t1 != NULL && t2 != NULL); 161 162 return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); 163 } 164 165 isc_result_t 166 isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) 167 { 168 ULARGE_INTEGER i1; 169 170 REQUIRE(t != NULL && i != NULL && result != NULL); 171 172 i1.LowPart = t->absolute.dwLowDateTime; 173 i1.HighPart = t->absolute.dwHighDateTime; 174 175 if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) 176 return (ISC_R_RANGE); 177 178 i1.QuadPart += i->interval; 179 180 result->absolute.dwLowDateTime = i1.LowPart; 181 result->absolute.dwHighDateTime = i1.HighPart; 182 183 return (ISC_R_SUCCESS); 184 } 185 186 isc_result_t 187 isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, 188 isc_time_t *result) { 189 ULARGE_INTEGER i1; 190 191 REQUIRE(t != NULL && i != NULL && result != NULL); 192 193 i1.LowPart = t->absolute.dwLowDateTime; 194 i1.HighPart = t->absolute.dwHighDateTime; 195 196 if (i1.QuadPart < (unsigned __int64) i->interval) 197 return (ISC_R_RANGE); 198 199 i1.QuadPart -= i->interval; 200 201 result->absolute.dwLowDateTime = i1.LowPart; 202 result->absolute.dwHighDateTime = i1.HighPart; 203 204 return (ISC_R_SUCCESS); 205 } 206 207 isc_uint64_t 208 isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { 209 ULARGE_INTEGER i1, i2; 210 LONGLONG i3; 211 212 REQUIRE(t1 != NULL && t2 != NULL); 213 214 i1.LowPart = t1->absolute.dwLowDateTime; 215 i1.HighPart = t1->absolute.dwHighDateTime; 216 i2.LowPart = t2->absolute.dwLowDateTime; 217 i2.HighPart = t2->absolute.dwHighDateTime; 218 219 if (i1.QuadPart <= i2.QuadPart) 220 return (0); 221 222 /* 223 * Convert to microseconds. 224 */ 225 i3 = (i1.QuadPart - i2.QuadPart) / 10; 226 227 return (i3); 228 } 229 230 isc_uint32_t 231 isc_time_seconds(const isc_time_t *t) { 232 SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; 233 FILETIME temp; 234 ULARGE_INTEGER i1, i2; 235 LONGLONG i3; 236 237 SystemTimeToFileTime(&epoch, &temp); 238 239 i1.LowPart = t->absolute.dwLowDateTime; 240 i1.HighPart = t->absolute.dwHighDateTime; 241 i2.LowPart = temp.dwLowDateTime; 242 i2.HighPart = temp.dwHighDateTime; 243 244 i3 = (i1.QuadPart - i2.QuadPart) / 10000000; 245 246 return ((isc_uint32_t)i3); 247 } 248 249 isc_result_t 250 isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { 251 time_t seconds; 252 253 REQUIRE(t != NULL); 254 255 seconds = (time_t)isc_time_seconds(t); 256 257 INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t)); 258 INSIST(sizeof(time_t) >= sizeof(isc_uint32_t)); 259 260 if (isc_time_seconds(t) > (~0U>>1) && seconds <= (time_t)(~0U>>1)) 261 return (ISC_R_RANGE); 262 263 *secondsp = seconds; 264 265 return (ISC_R_SUCCESS); 266 } 267 268 269 isc_uint32_t 270 isc_time_nanoseconds(const isc_time_t *t) { 271 ULARGE_INTEGER i; 272 273 i.LowPart = t->absolute.dwLowDateTime; 274 i.HighPart = t->absolute.dwHighDateTime; 275 return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); 276 } 277 278 void 279 isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { 280 FILETIME localft; 281 SYSTEMTIME st; 282 char DateBuf[50]; 283 char TimeBuf[50]; 284 285 static const char badtime[] = "99-Bad-9999 99:99:99.999"; 286 287 REQUIRE(len > 0); 288 if (FileTimeToLocalFileTime(&t->absolute, &localft) && 289 FileTimeToSystemTime(&localft, &st)) { 290 GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", 291 DateBuf, 50); 292 GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| 293 TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); 294 295 snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, 296 st.wMilliseconds); 297 298 } else 299 snprintf(buf, len, badtime); 300 } 301 302 void 303 isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { 304 SYSTEMTIME st; 305 char DateBuf[50]; 306 char TimeBuf[50]; 307 308 /* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ 309 310 REQUIRE(len > 0); 311 if (FileTimeToSystemTime(&t->absolute, &st)) { 312 GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 313 "ddd',' dd MMM yyyy", DateBuf, 50); 314 GetTimeFormat(LOCALE_USER_DEFAULT, 315 TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 316 &st, "hh':'mm':'ss", TimeBuf, 50); 317 318 snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); 319 } else { 320 buf[0] = 0; 321 } 322 } 323 324 isc_result_t 325 isc_time_parsehttptimestamp(char *buf, isc_time_t *t) { 326 struct tm t_tm; 327 time_t when; 328 char *p; 329 330 REQUIRE(buf != NULL); 331 REQUIRE(t != NULL); 332 p = isc_tm_strptime(buf, "%a, %d %b %Y %H:%M:%S", &t_tm); 333 if (p == NULL) 334 return (ISC_R_UNEXPECTED); 335 when = isc_tm_timegm(&t_tm); 336 if (when == -1) 337 return (ISC_R_UNEXPECTED); 338 isc_time_set(t, (unsigned int)when, 0); 339 return (ISC_R_SUCCESS); 340 } 341 342 void 343 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { 344 SYSTEMTIME st; 345 char DateBuf[50]; 346 char TimeBuf[50]; 347 348 /* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ 349 350 REQUIRE(len > 0); 351 if (FileTimeToSystemTime(&t->absolute, &st)) { 352 GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", 353 DateBuf, 50); 354 GetTimeFormat(LOCALE_NEUTRAL, 355 TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, 356 &st, "hh':'mm':'ss", TimeBuf, 50); 357 snprintf(buf, len, "%sT%sZ", DateBuf, TimeBuf); 358 } else { 359 buf[0] = 0; 360 } 361 } 362