diff options
Diffstat (limited to 'chrome/browser/sync/notifier/base/time.cc')
-rw-r--r-- | chrome/browser/sync/notifier/base/time.cc | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/chrome/browser/sync/notifier/base/time.cc b/chrome/browser/sync/notifier/base/time.cc new file mode 100644 index 0000000..ed3c414 --- /dev/null +++ b/chrome/browser/sync/notifier/base/time.cc @@ -0,0 +1,360 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/notifier/base/time.h" + +#include <string> +#include <time.h> + +#include "chrome/browser/sync/notifier/base/string.h" +#include "chrome/browser/sync/notifier/base/utils.h" +#include "talk/base/common.h" +#include "talk/base/logging.h" + +namespace notifier { + +// Get the current time represented in 100NS granularity since epoch +// (Jan 1, 1970) +time64 GetCurrent100NSTimeSinceEpoch() { + return GetCurrent100NSTime() - kStart100NsTimeToEpoch; +} + +char* GetLocalTimeAsString() { + time64 long_time = GetCurrent100NSTime(); + struct tm now; + Time64ToTm(long_time, &now); + char* time_string = asctime(&now); + if (time_string) { + int time_len = strlen(time_string); + if (time_len > 0) { + time_string[time_len - 1] = 0; // trim off terminating \n + } + } + return time_string; +} + +// Parses RFC 822 Date/Time format +// 5. DATE AND TIME SPECIFICATION +// 5.1. SYNTAX +// +// date-time = [ day "," ] date time ; dd mm yy +// ; hh:mm:ss zzz +// day = "Mon" / "Tue" / "Wed" / "Thu" +// / "Fri" / "Sat" / "Sun" +// +// date = 1*2DIGIT month 2DIGIT ; day month year +// ; e.g. 20 Jun 82 +// +// month = "Jan" / "Feb" / "Mar" / "Apr" +// / "May" / "Jun" / "Jul" / "Aug" +// / "Sep" / "Oct" / "Nov" / "Dec" +// +// time = hour zone ; ANSI and Military +// +// hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] +// ; 00:00:00 - 23:59:59 +// +// zone = "UT" / "GMT" ; Universal Time +// ; North American : UT +// / "EST" / "EDT" ; Eastern: - 5/ - 4 +// / "CST" / "CDT" ; Central: - 6/ - 5 +// / "MST" / "MDT" ; Mountain: - 7/ - 6 +// / "PST" / "PDT" ; Pacific: - 8/ - 7 +// / 1ALPHA ; Military: Z = UT; +// ; A:-1; (J not used) +// ; M:-12; N:+1; Y:+12 +// / ( ("+" / "-") 4DIGIT ) ; Local differential +// ; hours+min. (HHMM) +// Return local time if ret_local_time == true, return UTC time otherwise +const int kNumOfDays = 7; +const int kNumOfMonth = 12; +// Note: RFC822 does not include '-' as a separator, but Http Cookies use +// it in the date field, like this: Wdy, DD-Mon-YYYY HH:MM:SS GMT +// This differs from RFC822 only by those dashes. It is legacy quirk from +// old Netscape cookie specification. So it makes sense to expand this +// parser rather then add another one. +// See http://wp.netscape.com/newsref/std/cookie_spec.html +const char kRFC822_DateDelimiters[] = " ,:-"; + +const char kRFC822_TimeDelimiter[] = ": "; +const char* kRFC822_Day[] = { + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" +}; +const char* kRFC822_Month[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +struct TimeZoneInfo { + const char* zone_name; + int hour_dif; +}; + +const TimeZoneInfo kRFC822_TimeZone[] = { + { "UT", 0 }, + { "GMT", 0 }, + { "EST", -5 }, + { "EDT", -4 }, + { "CST", -6 }, + { "CDT", -5 }, + { "MST", -7 }, + { "MDT", -6 }, + { "PST", -8 }, + { "PDT", -7 }, + { "A", -1 }, // Military time zones + { "B", -2 }, + { "C", -3 }, + { "D", -4 }, + { "E", -5 }, + { "F", -6 }, + { "G", -7 }, + { "H", -8 }, + { "I", -9 }, + { "K", -10 }, + { "L", -11 }, + { "M", -12 }, + { "N", 1 }, + { "O", 2 }, + { "P", 3 }, + { "Q", 4 }, + { "R", 5 }, + { "S", 6 }, + { "T", 7 }, + { "U", 8 }, + { "V", 9 }, + { "W", 10 }, + { "X", 11 }, + { "Y", 12 }, + { "Z", 0 }, +}; + +bool ParseRFC822DateTime(const char* str, struct tm* time, + bool ret_local_time) { + ASSERT(str && *str); + ASSERT(time); + + std::string str_date(str); + std::string str_token; + const char* str_curr = str_date.c_str(); + + str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); + if (str_token == "") { + return false; + } + + for (int i = 0; i < kNumOfDays; ++i) { + if (str_token == kRFC822_Day[i]) { + // Skip spaces after ',' + while (*str_curr == ' ' && *str_curr != '\0') { + str_curr++; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); + if (str_token == "") { + return false; + } + break; + } + } + + int day = 0; + if (!ParseStringToInt(str_token.c_str(), &day, true) || day < 0 || day > 31) { + return false; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); + if (str_token == "") { + return false; + } + + int month = -1; + for (int i = 0; i < kNumOfMonth; ++i) { + if (str_token == kRFC822_Month[i]) { + month = i; // month is 0 based number + break; + } + } + if (month == -1) { // month not found + return false; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); + if (str_token == "") { + return false; + } + + int year = 0; + if (!ParseStringToInt(str_token.c_str(), &year, true)) { + return false; + } + if (year < 100) { // two digit year format, convert to 1950 - 2050 range + if (year < 50) { + year += 2000; + } else { + year += 1900; + } + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); + if (str_token == "") { + return false; + } + + int hour = 0; + if (!ParseStringToInt(str_token.c_str(), &hour, true) || + hour < 0 || hour > 23) { + return false; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); + if (str_token == "") { + return false; + } + + int minute = 0; + if (!ParseStringToInt(str_token.c_str(), &minute, true) || + minute < 0 || minute > 59) { + return false; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); + if (str_token == "") { + return false; + } + + int second = 0; + // distingushed between XX:XX and XX:XX:XX time formats + if (str_token.size() == 2 && isdigit(str_token[0]) && isdigit(str_token[1])) { + second = 0; + if (!ParseStringToInt(str_token.c_str(), &second, true) || + second < 0 || second > 59) { + return false; + } + + str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); + if (str_token == "") { + return false; + } + } + + int bias = 0; + if (str_token[0] == '+' || str_token[0] == '-' || isdigit(str_token[0])) { + // numeric format + int zone = 0; + if (!ParseStringToInt(str_token.c_str(), &zone, true)) { + return false; + } + + // zone is in HHMM format, need to convert to the number of minutes + bias = (zone / 100) * 60 + (zone % 100); + } else { // text format + for (size_t i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); + ++i) { + if (str_token == kRFC822_TimeZone[i].zone_name) { + bias = kRFC822_TimeZone[i].hour_dif * 60; + break; + } + } + } + + SetZero(*time); + time->tm_year = year - 1900; + time->tm_mon = month; + time->tm_mday = day; + time->tm_hour = hour; + time->tm_min = minute; + time->tm_sec = second; + + time64 time_64 = TmToTime64(*time); + time_64 = time_64 - bias * kMinsTo100ns; + + if (!Time64ToTm(time_64, time)) { + return false; + } + + if (ret_local_time) { + if (!UtcTimeToLocalTime(time)) { + return false; + } + } + + return true; +} + +// Parse a string to time span +// +// A TimeSpan value can be represented as +// [d.]hh:mm:ss +// +// d = days (optional) +// hh = hours as measured on a 24-hour clock +// mm = minutes +// ss = seconds +bool ParseStringToTimeSpan(const char* str, time64* time_span) { + ASSERT(str); + ASSERT(time_span); + + const char kColonDelimitor[] = ":"; + const char kDotDelimitor = '.'; + + std::string str_span(str); + time64 span = 0; + + int idx = str_span.find(kDotDelimitor); + if (idx != -1) { + std::string str_day = str_span.substr(0, idx); + int day = 0; + if (!ParseStringToInt(str_day.c_str(), &day, true) || + day < 0 || day > 365) { + return false; + } + span = day; + + str_span = str_span.substr(idx + 1); + } + + const char* str_curr = str_span.c_str(); + std::string str_token; + + str_token = SplitOneStringToken(&str_curr, kColonDelimitor); + if (str_token == "") { + return false; + } + + int hour = 0; + if (!ParseStringToInt(str_token.c_str(), &hour, true) || + hour < 0 || hour > 23) { + return false; + } + span = span * 24 + hour; + + str_token = SplitOneStringToken(&str_curr, kColonDelimitor); + if (str_token == "") { + return false; + } + + int minute = 0; + if (!ParseStringToInt(str_token.c_str(), &minute, true) || + minute < 0 || minute > 59) { + return false; + } + span = span * 60 + minute; + + str_token = SplitOneStringToken(&str_curr, kColonDelimitor); + if (str_token == "") { + return false; + } + + int second = 0; + if (!ParseStringToInt(str_token.c_str(), &second, true) || + second < 0 || second > 59) { + return false; + } + + *time_span = (span * 60 + second) * kSecsTo100ns; + + return true; +} + +} // namespace notifier |