1// Windows/TimeUtils.cpp 2 3#include "StdAfx.h" 4 5#ifndef _WIN32 6#include <sys/time.h> 7#endif 8 9#include "Defs.h" 10#include "TimeUtils.h" 11 12namespace NWindows { 13namespace NTime { 14 15static const UInt32 kNumTimeQuantumsInSecond = 10000000; 16static const UInt32 kFileTimeStartYear = 1601; 17#if !defined(_WIN32) || defined(UNDER_CE) 18static const UInt32 kDosTimeStartYear = 1980; 19#endif 20static const UInt32 kUnixTimeStartYear = 1970; 21static const UInt64 kUnixTimeOffset = 22 (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); 23static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; 24 25bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw() 26{ 27 #if defined(_WIN32) && !defined(UNDER_CE) 28 return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); 29 #else 30 ft.dwLowDateTime = 0; 31 ft.dwHighDateTime = 0; 32 UInt64 res; 33 if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F, 34 (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res)) 35 return false; 36 res *= kNumTimeQuantumsInSecond; 37 ft.dwLowDateTime = (UInt32)res; 38 ft.dwHighDateTime = (UInt32)(res >> 32); 39 return true; 40 #endif 41} 42 43static const UInt32 kHighDosTime = 0xFF9FBF7D; 44static const UInt32 kLowDosTime = 0x210000; 45 46bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw() 47{ 48 #if defined(_WIN32) && !defined(UNDER_CE) 49 50 WORD datePart, timePart; 51 if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart)) 52 { 53 dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime; 54 return false; 55 } 56 dosTime = (((UInt32)datePart) << 16) + timePart; 57 58 #else 59 60#define PERIOD_4 (4 * 365 + 1) 61#define PERIOD_100 (PERIOD_4 * 25 - 1) 62#define PERIOD_400 (PERIOD_100 * 4 + 1) 63 64 unsigned year, mon, day, hour, min, sec; 65 UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); 66 Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 67 unsigned temp; 68 UInt32 v; 69 v64 += (kNumTimeQuantumsInSecond * 2 - 1); 70 v64 /= kNumTimeQuantumsInSecond; 71 sec = (unsigned)(v64 % 60); 72 v64 /= 60; 73 min = (unsigned)(v64 % 60); 74 v64 /= 60; 75 hour = (unsigned)(v64 % 24); 76 v64 /= 24; 77 78 v = (UInt32)v64; 79 80 year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400); 81 v %= PERIOD_400; 82 83 temp = (unsigned)(v / PERIOD_100); 84 if (temp == 4) 85 temp = 3; 86 year += temp * 100; 87 v -= temp * PERIOD_100; 88 89 temp = v / PERIOD_4; 90 if (temp == 25) 91 temp = 24; 92 year += temp * 4; 93 v -= temp * PERIOD_4; 94 95 temp = v / 365; 96 if (temp == 4) 97 temp = 3; 98 year += temp; 99 v -= temp * 365; 100 101 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) 102 ms[1] = 29; 103 for (mon = 1; mon <= 12; mon++) 104 { 105 unsigned s = ms[mon - 1]; 106 if (v < s) 107 break; 108 v -= s; 109 } 110 day = (unsigned)v + 1; 111 112 dosTime = kLowDosTime; 113 if (year < kDosTimeStartYear) 114 return false; 115 year -= kDosTimeStartYear; 116 dosTime = kHighDosTime; 117 if (year >= 128) 118 return false; 119 dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1); 120 #endif 121 return true; 122} 123 124 125bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw() 126{ 127 FILETIME loc = { 0, 0 }; 128 const UInt64 u1 = FILETIME_To_UInt64(utc); 129 const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec. 130 if (u1 >= kDelta) 131 { 132 if (!FileTimeToLocalFileTime(&utc, &loc)) 133 loc = utc; 134 else 135 { 136 const UInt64 u2 = FILETIME_To_UInt64(loc); 137 const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2); 138 if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time 139 loc = utc; 140 } 141 } 142 return FileTime_To_DosTime(loc, dosTime); 143} 144 145UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw() 146{ 147 return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; 148} 149 150void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw() 151{ 152 const UInt64 v = UnixTime_To_FileTime64(unixTime); 153 ft.dwLowDateTime = (DWORD)v; 154 ft.dwHighDateTime = (DWORD)(v >> 32); 155} 156 157UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw() 158{ 159 return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; 160} 161 162 163bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw() 164{ 165 if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) 166 { 167 fileTime = (UInt64)(Int64)-1; 168 return false; 169 } 170 if (unixTime < -(Int64)kUnixTimeOffset) 171 { 172 fileTime = 0; 173 return false; 174 } 175 fileTime = UnixTime64_To_FileTime64(unixTime); 176 return true; 177} 178 179 180bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw() 181{ 182 UInt64 v; 183 const bool res = UnixTime64_To_FileTime64(unixTime, v); 184 ft.dwLowDateTime = (DWORD)v; 185 ft.dwHighDateTime = (DWORD)(v >> 32); 186 return res; 187} 188 189 190Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw() 191{ 192 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 193 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; 194} 195 196Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw() 197{ 198 const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 199 quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond); 200 return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; 201} 202 203bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw() 204{ 205 UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 206 winTime /= kNumTimeQuantumsInSecond; 207 if (winTime < kUnixTimeOffset) 208 { 209 unixTime = 0; 210 return false; 211 } 212 winTime -= kUnixTimeOffset; 213 if (winTime > (UInt32)0xFFFFFFFF) 214 { 215 unixTime = (UInt32)0xFFFFFFFF; 216 return false; 217 } 218 unixTime = (UInt32)winTime; 219 return true; 220} 221 222bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, 223 unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw() 224{ 225 resSeconds = 0; 226 if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 || 227 day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59) 228 return false; 229 UInt32 numYears = year - kFileTimeStartYear; 230 UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400; 231 Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 232 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) 233 ms[1] = 29; 234 month--; 235 for (unsigned i = 0; i < month; i++) 236 numDays += ms[i]; 237 numDays += day - 1; 238 resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec; 239 return true; 240} 241 242 243void GetCurUtc_FiTime(CFiTime &ft) throw() 244{ 245 #ifdef _WIN32 246 247 // Both variants provide same low resolution on WinXP: about 15 ms. 248 // But GetSystemTimeAsFileTime is much faster. 249 #ifdef UNDER_CE 250 SYSTEMTIME st; 251 GetSystemTime(&st); 252 SystemTimeToFileTime(&st, &ft); 253 #else 254 GetSystemTimeAsFileTime(&ft); 255 #endif 256 257 #else 258 259 FiTime_Clear(ft); 260 struct timeval now; 261 if (gettimeofday(&now, NULL) == 0) 262 { 263 ft.tv_sec = now.tv_sec; 264 ft.tv_nsec = now.tv_usec * 1000; 265 } 266 267 #endif 268} 269 270#ifndef _WIN32 271void GetCurUtcFileTime(FILETIME &ft) throw() 272{ 273 UInt64 v = 0; 274 struct timeval now; 275 if (gettimeofday(&now, NULL) == 0) 276 { 277 v = ((UInt64)now.tv_sec + kUnixTimeOffset) * 278 kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10; 279 } 280 ft.dwLowDateTime = (DWORD)v; 281 ft.dwHighDateTime = (DWORD)(v >> 32); 282} 283#endif 284 285 286}} 287 288 289#ifdef _WIN32 290 291/* 292void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) 293{ 294 if (prec == k_PropVar_TimePrec_0 295 || prec == k_PropVar_TimePrec_HighPrec 296 || prec >= k_PropVar_TimePrec_100ns) 297 return; 298 UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; 299 300 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; 301 UInt32 d; 302 if (prec == k_PropVar_TimePrec_DOS) 303 { 304 // we round up as windows DosDateTimeToFileTime() 305 v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1; 306 d = NWindows::NTime::kNumTimeQuantumsInSecond * 2; 307 } 308 else 309 { 310 if (prec == k_PropVar_TimePrec_Unix) 311 numDigits = 0; 312 else if (numDigits < 0) 313 return; 314 d = 1; 315 for (unsigned k = numDigits; k < 7; k++) 316 d *= 10; 317 } 318 v /= d; 319 v *= d; 320 ft.dwLowDateTime = (DWORD)v; 321 ft.dwHighDateTime = (DWORD)(v >> 32); 322} 323*/ 324 325#else 326 327/* 328void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) 329{ 330 if (prec >= k_PropVar_TimePrec_1ns 331 || prec == k_PropVar_TimePrec_HighPrec) 332 return; 333 334 int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; 335 UInt32 d; 336 if (prec == k_PropVar_TimePrec_Unix || 337 prec == (int)k_PropVar_TimePrec_Base) 338 { 339 ft.tv_nsec = 0; 340 return; 341 } 342 if (prec == k_PropVar_TimePrec_DOS) 343 { 344 // we round up as windows DosDateTimeToFileTime() 345 const unsigned sec1 = (ft.tv_sec & 1); 346 if (ft.tv_nsec == 0 && sec1 == 0) 347 return; 348 ft.tv_nsec = 0; 349 ft.tv_sec += 2 - sec1; 350 return; 351 } 352 { 353 if (prec == k_PropVar_TimePrec_0 354 || numDigits < 0) 355 numDigits = 7; 356 d = 1; 357 for (unsigned k = numDigits; k < 9; k++) 358 d *= 10; 359 ft.tv_nsec /= d; 360 ft.tv_nsec *= d; 361 } 362} 363*/ 364 365int Compare_FiTime(const CFiTime *a1, const CFiTime *a2) 366{ 367 if (a1->tv_sec < a2->tv_sec) return -1; 368 if (a1->tv_sec > a2->tv_sec) return 1; 369 if (a1->tv_nsec < a2->tv_nsec) return -1; 370 if (a1->tv_nsec > a2->tv_nsec) return 1; 371 return 0; 372} 373 374bool FILETIME_To_timespec(const FILETIME &ft, timespec &ts) 375{ 376 UInt32 quantums; 377 const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums); 378 // time_t is long 379 const time_t sec2 = (time_t)sec; 380 if (sec2 == sec) 381 { 382 ts.tv_sec = sec2; 383 ts.tv_nsec = (long)(quantums * 100); 384 return true; 385 } 386 return false; 387} 388 389void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100) 390{ 391 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); 392 ns100 = (unsigned)((UInt64)ts.tv_nsec % 100); 393 ft.dwLowDateTime = (DWORD)v; 394 ft.dwHighDateTime = (DWORD)(v >> 32); 395} 396 397void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) 398{ 399 const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); 400 ft.dwLowDateTime = (DWORD)v; 401 ft.dwHighDateTime = (DWORD)(v >> 32); 402} 403 404#endif 405