| OLD | NEW |
| (Empty) |
| 1 // Copyright 2004-2009 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 // | |
| 16 // Time functions | |
| 17 | |
| 18 #include "omaha/base/time.h" | |
| 19 #include "omaha/base/commontypes.h" | |
| 20 #include "omaha/base/debug.h" | |
| 21 #include "omaha/base/error.h" | |
| 22 #include "omaha/base/logging.h" | |
| 23 #include "omaha/base/string.h" | |
| 24 #include "omaha/base/utils.h" | |
| 25 | |
| 26 namespace omaha { | |
| 27 | |
| 28 // Date Constants | |
| 29 | |
| 30 #define kNumOfDays 7 | |
| 31 #define kNumOfMonth 12 | |
| 32 | |
| 33 static const TCHAR kRFC822_DateDelimiters[] = _T(" ,:"); | |
| 34 static const TCHAR kRFC822_TimeDelimiter[] = _T(":"); | |
| 35 SELECTANY const TCHAR* kRFC822_Day[kNumOfDays] = { | |
| 36 _T("Mon"), | |
| 37 _T("Tue"), | |
| 38 _T("Wed"), | |
| 39 _T("Thu"), | |
| 40 _T("Fri"), | |
| 41 _T("Sat"), | |
| 42 _T("Sun") }; | |
| 43 | |
| 44 SELECTANY const TCHAR* kRFC822_Month[kNumOfMonth] = { | |
| 45 _T("Jan"), | |
| 46 _T("Feb"), | |
| 47 _T("Mar"), | |
| 48 _T("Apr"), | |
| 49 _T("May"), | |
| 50 _T("Jun"), | |
| 51 _T("Jul"), | |
| 52 _T("Aug"), | |
| 53 _T("Sep"), | |
| 54 _T("Oct"), | |
| 55 _T("Nov"), | |
| 56 _T("Dec") }; | |
| 57 | |
| 58 struct TimeZoneInfo { | |
| 59 const TCHAR* zone_name; | |
| 60 int hour_dif; | |
| 61 }; | |
| 62 | |
| 63 SELECTANY TimeZoneInfo kRFC822_TimeZone[] = { | |
| 64 { _T("UT"), 0 }, | |
| 65 { _T("GMT"), 0 }, | |
| 66 { _T("EST"), -5 }, | |
| 67 { _T("EDT"), -4 }, | |
| 68 { _T("CST"), -6 }, | |
| 69 { _T("CDT"), -5 }, | |
| 70 { _T("MST"), -7 }, | |
| 71 { _T("MDT"), -6 }, | |
| 72 { _T("PST"), -8 }, | |
| 73 { _T("PDT"), -7 }, | |
| 74 { _T("A"), -1 }, // Military time zones | |
| 75 { _T("B"), -2 }, | |
| 76 { _T("C"), -3 }, | |
| 77 { _T("D"), -4 }, | |
| 78 { _T("E"), -5 }, | |
| 79 { _T("F"), -6 }, | |
| 80 { _T("G"), -7 }, | |
| 81 { _T("H"), -8 }, | |
| 82 { _T("I"), -9 }, | |
| 83 { _T("K"), -10 }, | |
| 84 { _T("L"), -11 }, | |
| 85 { _T("M"), -12 }, | |
| 86 { _T("N"), 1 }, | |
| 87 { _T("O"), 2 }, | |
| 88 { _T("P"), 3 }, | |
| 89 { _T("Q"), 4 }, | |
| 90 { _T("R"), 5 }, | |
| 91 { _T("S"), 6 }, | |
| 92 { _T("T"), 7 }, | |
| 93 { _T("U"), 8 }, | |
| 94 { _T("V"), 9 }, | |
| 95 { _T("W"), 10 }, | |
| 96 { _T("X"), 11 }, | |
| 97 { _T("Y"), 12 }, | |
| 98 { _T("Z"), 0 }, | |
| 99 }; | |
| 100 | |
| 101 SELECTANY const TCHAR *days[] = | |
| 102 { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" }; | |
| 103 | |
| 104 SELECTANY const TCHAR *months[] = { | |
| 105 L"Jan", | |
| 106 L"Feb", | |
| 107 L"Mar", | |
| 108 L"Apr", | |
| 109 L"May", | |
| 110 L"Jun", | |
| 111 L"Jul", | |
| 112 L"Aug", | |
| 113 L"Sep", | |
| 114 L"Oct", | |
| 115 L"Nov", | |
| 116 L"Dec" | |
| 117 }; | |
| 118 | |
| 119 // NOTE: so long as the output is used internally only, no localization is | |
| 120 // needed here. | |
| 121 CString ConvertTimeToGMTString(const FILETIME *ft) { | |
| 122 ASSERT(ft, (L"")); | |
| 123 | |
| 124 CString s; | |
| 125 SYSTEMTIME st; | |
| 126 if (!FileTimeToSystemTime(ft, &st)) { | |
| 127 return L""; | |
| 128 } | |
| 129 | |
| 130 // same as FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT")); | |
| 131 s.Format(NOTRANSL(L"%s, %02d %s %d %02d:%02d:%02d GMT"), days[st.wDayOfWeek], | |
| 132 st.wDay, months[st.wMonth-1], st.wYear, st.wHour, st.wMinute, st.wSecond); | |
| 133 return s; | |
| 134 } | |
| 135 | |
| 136 time64 ConvertTime16ToTime64(uint16 time16) { | |
| 137 return time16 * kTimeGranularity + kStart100NsTime; | |
| 138 } | |
| 139 | |
| 140 uint16 ConvertTime64ToTime16(time64 time) { | |
| 141 ASSERT1(time >= kStart100NsTime); | |
| 142 | |
| 143 time64 t64 = (time - kStart100NsTime) / kTimeGranularity; | |
| 144 ASSERT1(t64 <= kTime16Max); | |
| 145 | |
| 146 return static_cast<uint16>(t64); | |
| 147 } | |
| 148 | |
| 149 time64 TimeTToTime64(const time_t& old_value) { | |
| 150 FILETIME file_time; | |
| 151 TimeTToFileTime(old_value, &file_time); | |
| 152 return FileTimeToTime64(file_time); | |
| 153 } | |
| 154 | |
| 155 #ifdef _DEBUG | |
| 156 void ComputeStartTime() { | |
| 157 SYSTEMTIME start_system_time = kStartSystemTime; | |
| 158 time64 start_100ns_time = SystemTimeToTime64(&start_system_time); | |
| 159 UTIL_LOG(L1, (_T("posting list starting time = %s\n"), | |
| 160 String_Int64ToString(start_100ns_time, 10))); | |
| 161 } | |
| 162 #endif | |
| 163 | |
| 164 // Time management | |
| 165 | |
| 166 // Allow the unittest to override. | |
| 167 static time64 time_override = 0; | |
| 168 | |
| 169 // #ifdef UNITTEST | |
| 170 void SetTimeOverride(const time64 & time_new) { | |
| 171 time_override = time_new; | |
| 172 } | |
| 173 | |
| 174 // #endif | |
| 175 | |
| 176 time64 GetCurrent100NSTime() { | |
| 177 if (time_override != 0) | |
| 178 return time_override; | |
| 179 | |
| 180 // In order gte the 100ns time we shouldn't use SystemTime | |
| 181 // as it's granularity is 1 ms. Below is the correct implementation. | |
| 182 // On the other hand the system clock granularity is 15 ms, so we | |
| 183 // are not gaining much by having the timestamp in nano-sec | |
| 184 // If we decide to go with ms, divide "time64 time" by 10000 | |
| 185 // SYSTEMTIME sys_time; | |
| 186 // GetLocalTime(&sys_time); | |
| 187 // return SystemTimeToTime64(&sys_time); | |
| 188 | |
| 189 // get the current time in 100-nanoseconds intervals | |
| 190 FILETIME file_time; | |
| 191 ::GetSystemTimeAsFileTime(&file_time); | |
| 192 | |
| 193 time64 time = FileTimeToTime64(file_time); | |
| 194 return time; | |
| 195 } | |
| 196 | |
| 197 time64 GetCurrentMsTime() { | |
| 198 return GetCurrent100NSTime() / kMillisecsTo100ns; | |
| 199 } | |
| 200 | |
| 201 time64 SystemTimeToTime64(const SYSTEMTIME* sys_time) { | |
| 202 ASSERT1(sys_time); | |
| 203 | |
| 204 FILETIME file_time; | |
| 205 SetZero(file_time); | |
| 206 | |
| 207 if (!::SystemTimeToFileTime(sys_time, &file_time)) { | |
| 208 UTIL_LOG(LE, | |
| 209 (_T("[SystemTimeToTime64 - failed to SystemTimeToFileTime][0x%x]"), | |
| 210 HRESULTFromLastError())); | |
| 211 return 0; | |
| 212 } | |
| 213 | |
| 214 return FileTimeToTime64(file_time); | |
| 215 } | |
| 216 | |
| 217 // returns a value compatible with EXE/DLL timestamps | |
| 218 // and the C time() function | |
| 219 // NOTE: behavior is independent of wMilliseconds value | |
| 220 int32 SystemTimeToInt32(const SYSTEMTIME *sys_time) { | |
| 221 ASSERT(sys_time, (L"")); | |
| 222 | |
| 223 time64 t64 = SystemTimeToTime64(sys_time); | |
| 224 int32 t32 = 0; | |
| 225 | |
| 226 if (t64 != 0) { | |
| 227 t32 = Time64ToInt32(t64); | |
| 228 } | |
| 229 return t32; | |
| 230 } | |
| 231 | |
| 232 int32 Time64ToInt32(const time64 & time) { | |
| 233 // convert to 32-bit format | |
| 234 // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC) | |
| 235 // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC) | |
| 236 | |
| 237 // seconds between 1601 and 1970 | |
| 238 time64 t32 = (time / kSecsTo100ns) - | |
| 239 ((time64(60*60*24) * time64(365*369 + 89))); | |
| 240 ASSERT(t32 == (t32 & 0x7FFFFFFF), (L"")); // make sure it fits | |
| 241 | |
| 242 // cast at the end (avoids overflow/underflow when computing 32-bit value) | |
| 243 return static_cast<int32>(t32); | |
| 244 } | |
| 245 | |
| 246 time64 Int32ToTime64(const int32 & time) { | |
| 247 // convert to 64-bit format | |
| 248 // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC) | |
| 249 // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC) | |
| 250 | |
| 251 // seconds between 1601 and 1970 | |
| 252 time64 t64 = (static_cast<time64>(time) + | |
| 253 (time64(60*60*24) * time64(365*369 + 89))) * kSecsTo100ns; | |
| 254 return t64; | |
| 255 } | |
| 256 | |
| 257 // TODO(omaha): The next 2 functions can fail if FileTimeToLocalFileTime or | |
| 258 // FileTimeToSystemTime fails. | |
| 259 // Consider having it return a HRESULT. Right now if FileTimeToSystemTime fails, | |
| 260 // it returns an undefined value. | |
| 261 | |
| 262 // Convert a uint to a genuine systemtime | |
| 263 SYSTEMTIME Time64ToSystemTime(const time64& time) { | |
| 264 FILETIME file_time; | |
| 265 SetZero(file_time); | |
| 266 Time64ToFileTime(time, &file_time); | |
| 267 | |
| 268 SYSTEMTIME sys_time; | |
| 269 SetZero(sys_time); | |
| 270 if (!FileTimeToSystemTime(&file_time, &sys_time)) { | |
| 271 UTIL_LOG(LE, (_T("[Time64ToSystemTime]") | |
| 272 _T("[failed to FileTimeToSystemTime][0x%x]"), | |
| 273 HRESULTFromLastError())); | |
| 274 } | |
| 275 | |
| 276 return sys_time; | |
| 277 } | |
| 278 | |
| 279 | |
| 280 // Convert a uint to a genuine localtime | |
| 281 // Should ONLY be used for display, since internally we use only UTC | |
| 282 SYSTEMTIME Time64ToLocalTime(const time64& time) { | |
| 283 FILETIME file_time; | |
| 284 SetZero(file_time); | |
| 285 Time64ToFileTime(time, &file_time); | |
| 286 | |
| 287 FILETIME local_file_time; | |
| 288 SetZero(local_file_time); | |
| 289 if (!FileTimeToLocalFileTime(&file_time, &local_file_time)) { | |
| 290 UTIL_LOG(LE, (_T("[Time64ToLocalTime]") | |
| 291 _T("[failed to FileTimeToLocalFileTime][0x%x]"), | |
| 292 HRESULTFromLastError())); | |
| 293 } | |
| 294 | |
| 295 SYSTEMTIME local_time; | |
| 296 SetZero(local_time); | |
| 297 if (!FileTimeToSystemTime(&local_file_time, &local_time)) { | |
| 298 UTIL_LOG(LE, (_T("[Time64ToLocalTime]") | |
| 299 _T("[failed to FileTimeToSystemTime][0x%x]"), | |
| 300 HRESULTFromLastError())); | |
| 301 } | |
| 302 | |
| 303 return local_time; | |
| 304 } | |
| 305 | |
| 306 time64 FileTimeToTime64(const FILETIME & file_time) { | |
| 307 return static_cast<time64>( | |
| 308 file_time.dwHighDateTime) << 32 | file_time.dwLowDateTime; | |
| 309 } | |
| 310 | |
| 311 void Time64ToFileTime(const time64 & time, FILETIME *ft) { | |
| 312 ASSERT(ft, (L"")); | |
| 313 | |
| 314 ft->dwHighDateTime = static_cast<DWORD>(time >> 32); | |
| 315 ft->dwLowDateTime = static_cast<DWORD>(time & 0xffffffff); | |
| 316 } | |
| 317 | |
| 318 // Convert from FILETIME to time_t | |
| 319 time_t FileTimeToTimeT(const FILETIME& file_time) { | |
| 320 return static_cast<time_t>( | |
| 321 (FileTimeToTime64(file_time) - kTimeTConvValue) / kSecsTo100ns); | |
| 322 } | |
| 323 | |
| 324 // Convert from time_t to FILETIME | |
| 325 void TimeTToFileTime(const time_t& time, FILETIME* file_time) { | |
| 326 ASSERT1(file_time); | |
| 327 | |
| 328 LONGLONG ll = Int32x32To64(time, kSecsTo100ns) + kTimeTConvValue; | |
| 329 file_time->dwLowDateTime = static_cast<DWORD>(ll); | |
| 330 file_time->dwHighDateTime = static_cast<DWORD>(ll >> 32); | |
| 331 } | |
| 332 | |
| 333 // Parses RFC 822 Date/Time format | |
| 334 // 5. DATE AND TIME SPECIFICATION | |
| 335 // 5.1. SYNTAX | |
| 336 // | |
| 337 // date-time = [ day "," ] date time ; dd mm yy | |
| 338 // ; hh:mm:ss zzz | |
| 339 // day = "Mon" / "Tue" / "Wed" / "Thu" | |
| 340 // / "Fri" / "Sat" / "Sun" | |
| 341 // | |
| 342 // date = 1*2DIGIT month 2DIGIT ; day month year | |
| 343 // ; e.g. 20 Jun 82 | |
| 344 // | |
| 345 // month = "Jan" / "Feb" / "Mar" / "Apr" | |
| 346 // / "May" / "Jun" / "Jul" / "Aug" | |
| 347 // / "Sep" / "Oct" / "Nov" / "Dec" | |
| 348 // | |
| 349 // time = hour zone ; ANSI and Military | |
| 350 // | |
| 351 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] | |
| 352 // ; 00:00:00 - 23:59:59 | |
| 353 // | |
| 354 // zone = "UT" / "GMT" ; Universal Time | |
| 355 // ; North American : UT | |
| 356 // / "EST" / "EDT" ; Eastern: - 5/ - 4 | |
| 357 // / "CST" / "CDT" ; Central: - 6/ - 5 | |
| 358 // / "MST" / "MDT" ; Mountain: - 7/ - 6 | |
| 359 // / "PST" / "PDT" ; Pacific: - 8/ - 7 | |
| 360 // / 1ALPHA ; Military: Z = UT; | |
| 361 // ; A:-1; (J not used) | |
| 362 // ; M:-12; N:+1; Y:+12 | |
| 363 // / ( ("+" / "-") 4DIGIT ) ; Local differential | |
| 364 // ; hours+min. (HHMM) | |
| 365 // return local time if ret_local_time == true, | |
| 366 // return time is GMT / UTC time otherwise | |
| 367 bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date, | |
| 368 SYSTEMTIME* psys_time, | |
| 369 bool ret_local_time) { | |
| 370 ASSERT(str_RFC822_date != NULL, (L"")); | |
| 371 ASSERT(psys_time != NULL, (L"")); | |
| 372 | |
| 373 CString str_date = str_RFC822_date; | |
| 374 CString str_token; | |
| 375 int cur_pos = 0; | |
| 376 | |
| 377 str_token= str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 378 if (str_token == "") | |
| 379 return false; | |
| 380 | |
| 381 int i = 0; | |
| 382 for (i = 0; i < kNumOfDays; i++) { | |
| 383 if (str_token == kRFC822_Day[i]) { | |
| 384 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 385 if (str_token == "") | |
| 386 return false; | |
| 387 break; | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 int day = String_StringToInt(str_token); | |
| 392 if (day < 0 || day > 31) | |
| 393 return false; | |
| 394 | |
| 395 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 396 if (str_token == "") | |
| 397 return false; | |
| 398 | |
| 399 int month = -1; | |
| 400 for (i = 0; i < kNumOfMonth; i++) { | |
| 401 if (str_token == kRFC822_Month[i]) { | |
| 402 month = i+1; // month is 1 based number | |
| 403 break; | |
| 404 } | |
| 405 } | |
| 406 if (month == -1) // month not found | |
| 407 return false; | |
| 408 | |
| 409 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 410 if (str_token == "") | |
| 411 return false; | |
| 412 | |
| 413 int year = String_StringToInt(str_token); | |
| 414 if (year < 100) // two digit year format, convert to 1950 - 2050 range | |
| 415 if (year < 50) | |
| 416 year += 2000; | |
| 417 else | |
| 418 year += 1900; | |
| 419 | |
| 420 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 421 if (str_token == "") | |
| 422 return false; | |
| 423 | |
| 424 int hour = String_StringToInt(str_token); | |
| 425 if (hour < 0 || hour > 23) | |
| 426 return false; | |
| 427 | |
| 428 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 429 if (str_token == "") | |
| 430 return false; | |
| 431 | |
| 432 int minute = String_StringToInt(str_token); | |
| 433 if (minute < 0 || minute > 59) | |
| 434 return false; | |
| 435 | |
| 436 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 437 if (str_token == "") | |
| 438 return false; | |
| 439 | |
| 440 int second = 0; | |
| 441 // distingushed between XX:XX and XX:XX:XX time formats | |
| 442 if (str_token.GetLength() == 2 && | |
| 443 String_IsDigit(str_token[0]) && | |
| 444 String_IsDigit(str_token[1])) { | |
| 445 second = String_StringToInt(str_token); | |
| 446 if (second < 0 || second > 59) | |
| 447 return false; | |
| 448 | |
| 449 str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos); | |
| 450 if (str_token == "") | |
| 451 return false; | |
| 452 } | |
| 453 | |
| 454 int bias = 0; | |
| 455 if (str_token[0] == '+' || | |
| 456 str_token[0] == '-' || | |
| 457 String_IsDigit(str_token[0])) { // numeric format | |
| 458 int zone = String_StringToInt(str_token); | |
| 459 | |
| 460 // zone is in HHMM format, need to convert to the number of minutes | |
| 461 bias = (zone / 100) * 60 + (zone % 100); | |
| 462 } else { // text format | |
| 463 for (i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); i++) | |
| 464 if (str_token == kRFC822_TimeZone[i].zone_name) { | |
| 465 bias = kRFC822_TimeZone[i].hour_dif * 60; | |
| 466 break; | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 SYSTEMTIME mail_time; | |
| 471 memset(&mail_time, 0, sizeof(mail_time)); | |
| 472 | |
| 473 mail_time.wYear = static_cast<WORD>(year); | |
| 474 mail_time.wMonth = static_cast<WORD>(month); | |
| 475 mail_time.wDay = static_cast<WORD>(day); | |
| 476 mail_time.wHour = static_cast<WORD>(hour); | |
| 477 mail_time.wMinute = static_cast<WORD>(minute); | |
| 478 mail_time.wSecond = static_cast<WORD>(second); | |
| 479 | |
| 480 // TzSpecificLocalTimeToSystemTime() is incompatible with Win 2000, | |
| 481 // convert time manually here | |
| 482 time64 time_64 = SystemTimeToTime64(&mail_time); | |
| 483 time_64 = time_64 - (bias*kMinsTo100ns); | |
| 484 | |
| 485 *psys_time = Time64ToSystemTime(time_64); | |
| 486 | |
| 487 if (ret_local_time) { | |
| 488 TIME_ZONE_INFORMATION local_time_zone_info; | |
| 489 SYSTEMTIME universal_time = *psys_time; | |
| 490 | |
| 491 if (GetTimeZoneInformation(&local_time_zone_info) == TIME_ZONE_ID_INVALID) { | |
| 492 return false; | |
| 493 } | |
| 494 if (!SystemTimeToTzSpecificLocalTime(&local_time_zone_info, | |
| 495 &universal_time, | |
| 496 psys_time)) { | |
| 497 return false; | |
| 498 } | |
| 499 } | |
| 500 return true; | |
| 501 } | |
| 502 | |
| 503 } // namespace omaha | |
| 504 | |
| OLD | NEW |