OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/sync/notifier/base/time.h" |
| 6 |
| 7 #include <string> |
| 8 #include <time.h> |
| 9 |
| 10 #include "chrome/browser/sync/notifier/base/string.h" |
| 11 #include "chrome/browser/sync/notifier/base/utils.h" |
| 12 #include "talk/base/common.h" |
| 13 #include "talk/base/logging.h" |
| 14 |
| 15 namespace notifier { |
| 16 |
| 17 // Get the current time represented in 100NS granularity since epoch |
| 18 // (Jan 1, 1970) |
| 19 time64 GetCurrent100NSTimeSinceEpoch() { |
| 20 return GetCurrent100NSTime() - kStart100NsTimeToEpoch; |
| 21 } |
| 22 |
| 23 char* GetLocalTimeAsString() { |
| 24 time64 long_time = GetCurrent100NSTime(); |
| 25 struct tm now; |
| 26 Time64ToTm(long_time, &now); |
| 27 char* time_string = asctime(&now); |
| 28 if (time_string) { |
| 29 int time_len = strlen(time_string); |
| 30 if (time_len > 0) { |
| 31 time_string[time_len - 1] = 0; // trim off terminating \n |
| 32 } |
| 33 } |
| 34 return time_string; |
| 35 } |
| 36 |
| 37 // Parses RFC 822 Date/Time format |
| 38 // 5. DATE AND TIME SPECIFICATION |
| 39 // 5.1. SYNTAX |
| 40 // |
| 41 // date-time = [ day "," ] date time ; dd mm yy |
| 42 // ; hh:mm:ss zzz |
| 43 // day = "Mon" / "Tue" / "Wed" / "Thu" |
| 44 // / "Fri" / "Sat" / "Sun" |
| 45 // |
| 46 // date = 1*2DIGIT month 2DIGIT ; day month year |
| 47 // ; e.g. 20 Jun 82 |
| 48 // |
| 49 // month = "Jan" / "Feb" / "Mar" / "Apr" |
| 50 // / "May" / "Jun" / "Jul" / "Aug" |
| 51 // / "Sep" / "Oct" / "Nov" / "Dec" |
| 52 // |
| 53 // time = hour zone ; ANSI and Military |
| 54 // |
| 55 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] |
| 56 // ; 00:00:00 - 23:59:59 |
| 57 // |
| 58 // zone = "UT" / "GMT" ; Universal Time |
| 59 // ; North American : UT |
| 60 // / "EST" / "EDT" ; Eastern: - 5/ - 4 |
| 61 // / "CST" / "CDT" ; Central: - 6/ - 5 |
| 62 // / "MST" / "MDT" ; Mountain: - 7/ - 6 |
| 63 // / "PST" / "PDT" ; Pacific: - 8/ - 7 |
| 64 // / 1ALPHA ; Military: Z = UT; |
| 65 // ; A:-1; (J not used) |
| 66 // ; M:-12; N:+1; Y:+12 |
| 67 // / ( ("+" / "-") 4DIGIT ) ; Local differential |
| 68 // ; hours+min. (HHMM) |
| 69 // Return local time if ret_local_time == true, return UTC time otherwise |
| 70 const int kNumOfDays = 7; |
| 71 const int kNumOfMonth = 12; |
| 72 // Note: RFC822 does not include '-' as a separator, but Http Cookies use |
| 73 // it in the date field, like this: Wdy, DD-Mon-YYYY HH:MM:SS GMT |
| 74 // This differs from RFC822 only by those dashes. It is legacy quirk from |
| 75 // old Netscape cookie specification. So it makes sense to expand this |
| 76 // parser rather then add another one. |
| 77 // See http://wp.netscape.com/newsref/std/cookie_spec.html |
| 78 const char kRFC822_DateDelimiters[] = " ,:-"; |
| 79 |
| 80 const char kRFC822_TimeDelimiter[] = ": "; |
| 81 const char* kRFC822_Day[] = { |
| 82 "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" |
| 83 }; |
| 84 const char* kRFC822_Month[] = { |
| 85 "Jan", "Feb", "Mar", "Apr", "May", "Jun", |
| 86 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
| 87 }; |
| 88 |
| 89 struct TimeZoneInfo { |
| 90 const char* zone_name; |
| 91 int hour_dif; |
| 92 }; |
| 93 |
| 94 const TimeZoneInfo kRFC822_TimeZone[] = { |
| 95 { "UT", 0 }, |
| 96 { "GMT", 0 }, |
| 97 { "EST", -5 }, |
| 98 { "EDT", -4 }, |
| 99 { "CST", -6 }, |
| 100 { "CDT", -5 }, |
| 101 { "MST", -7 }, |
| 102 { "MDT", -6 }, |
| 103 { "PST", -8 }, |
| 104 { "PDT", -7 }, |
| 105 { "A", -1 }, // Military time zones |
| 106 { "B", -2 }, |
| 107 { "C", -3 }, |
| 108 { "D", -4 }, |
| 109 { "E", -5 }, |
| 110 { "F", -6 }, |
| 111 { "G", -7 }, |
| 112 { "H", -8 }, |
| 113 { "I", -9 }, |
| 114 { "K", -10 }, |
| 115 { "L", -11 }, |
| 116 { "M", -12 }, |
| 117 { "N", 1 }, |
| 118 { "O", 2 }, |
| 119 { "P", 3 }, |
| 120 { "Q", 4 }, |
| 121 { "R", 5 }, |
| 122 { "S", 6 }, |
| 123 { "T", 7 }, |
| 124 { "U", 8 }, |
| 125 { "V", 9 }, |
| 126 { "W", 10 }, |
| 127 { "X", 11 }, |
| 128 { "Y", 12 }, |
| 129 { "Z", 0 }, |
| 130 }; |
| 131 |
| 132 bool ParseRFC822DateTime(const char* str, struct tm* time, |
| 133 bool ret_local_time) { |
| 134 ASSERT(str && *str); |
| 135 ASSERT(time); |
| 136 |
| 137 std::string str_date(str); |
| 138 std::string str_token; |
| 139 const char* str_curr = str_date.c_str(); |
| 140 |
| 141 str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); |
| 142 if (str_token == "") { |
| 143 return false; |
| 144 } |
| 145 |
| 146 for (int i = 0; i < kNumOfDays; ++i) { |
| 147 if (str_token == kRFC822_Day[i]) { |
| 148 // Skip spaces after ',' |
| 149 while (*str_curr == ' ' && *str_curr != '\0') { |
| 150 str_curr++; |
| 151 } |
| 152 |
| 153 str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); |
| 154 if (str_token == "") { |
| 155 return false; |
| 156 } |
| 157 break; |
| 158 } |
| 159 } |
| 160 |
| 161 int day = 0; |
| 162 if (!ParseStringToInt(str_token.c_str(), &day, true) || day < 0 || day > 31) { |
| 163 return false; |
| 164 } |
| 165 |
| 166 str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); |
| 167 if (str_token == "") { |
| 168 return false; |
| 169 } |
| 170 |
| 171 int month = -1; |
| 172 for (int i = 0; i < kNumOfMonth; ++i) { |
| 173 if (str_token == kRFC822_Month[i]) { |
| 174 month = i; // month is 0 based number |
| 175 break; |
| 176 } |
| 177 } |
| 178 if (month == -1) { // month not found |
| 179 return false; |
| 180 } |
| 181 |
| 182 str_token = SplitOneStringToken(&str_curr, kRFC822_DateDelimiters); |
| 183 if (str_token == "") { |
| 184 return false; |
| 185 } |
| 186 |
| 187 int year = 0; |
| 188 if (!ParseStringToInt(str_token.c_str(), &year, true)) { |
| 189 return false; |
| 190 } |
| 191 if (year < 100) { // two digit year format, convert to 1950 - 2050 range |
| 192 if (year < 50) { |
| 193 year += 2000; |
| 194 } else { |
| 195 year += 1900; |
| 196 } |
| 197 } |
| 198 |
| 199 str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); |
| 200 if (str_token == "") { |
| 201 return false; |
| 202 } |
| 203 |
| 204 int hour = 0; |
| 205 if (!ParseStringToInt(str_token.c_str(), &hour, true) || |
| 206 hour < 0 || hour > 23) { |
| 207 return false; |
| 208 } |
| 209 |
| 210 str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); |
| 211 if (str_token == "") { |
| 212 return false; |
| 213 } |
| 214 |
| 215 int minute = 0; |
| 216 if (!ParseStringToInt(str_token.c_str(), &minute, true) || |
| 217 minute < 0 || minute > 59) { |
| 218 return false; |
| 219 } |
| 220 |
| 221 str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); |
| 222 if (str_token == "") { |
| 223 return false; |
| 224 } |
| 225 |
| 226 int second = 0; |
| 227 // distingushed between XX:XX and XX:XX:XX time formats |
| 228 if (str_token.size() == 2 && isdigit(str_token[0]) && isdigit(str_token[1])) { |
| 229 second = 0; |
| 230 if (!ParseStringToInt(str_token.c_str(), &second, true) || |
| 231 second < 0 || second > 59) { |
| 232 return false; |
| 233 } |
| 234 |
| 235 str_token = SplitOneStringToken(&str_curr, kRFC822_TimeDelimiter); |
| 236 if (str_token == "") { |
| 237 return false; |
| 238 } |
| 239 } |
| 240 |
| 241 int bias = 0; |
| 242 if (str_token[0] == '+' || str_token[0] == '-' || isdigit(str_token[0])) { |
| 243 // numeric format |
| 244 int zone = 0; |
| 245 if (!ParseStringToInt(str_token.c_str(), &zone, true)) { |
| 246 return false; |
| 247 } |
| 248 |
| 249 // zone is in HHMM format, need to convert to the number of minutes |
| 250 bias = (zone / 100) * 60 + (zone % 100); |
| 251 } else { // text format |
| 252 for (size_t i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); |
| 253 ++i) { |
| 254 if (str_token == kRFC822_TimeZone[i].zone_name) { |
| 255 bias = kRFC822_TimeZone[i].hour_dif * 60; |
| 256 break; |
| 257 } |
| 258 } |
| 259 } |
| 260 |
| 261 SetZero(*time); |
| 262 time->tm_year = year - 1900; |
| 263 time->tm_mon = month; |
| 264 time->tm_mday = day; |
| 265 time->tm_hour = hour; |
| 266 time->tm_min = minute; |
| 267 time->tm_sec = second; |
| 268 |
| 269 time64 time_64 = TmToTime64(*time); |
| 270 time_64 = time_64 - bias * kMinsTo100ns; |
| 271 |
| 272 if (!Time64ToTm(time_64, time)) { |
| 273 return false; |
| 274 } |
| 275 |
| 276 if (ret_local_time) { |
| 277 if (!UtcTimeToLocalTime(time)) { |
| 278 return false; |
| 279 } |
| 280 } |
| 281 |
| 282 return true; |
| 283 } |
| 284 |
| 285 // Parse a string to time span |
| 286 // |
| 287 // A TimeSpan value can be represented as |
| 288 // [d.]hh:mm:ss |
| 289 // |
| 290 // d = days (optional) |
| 291 // hh = hours as measured on a 24-hour clock |
| 292 // mm = minutes |
| 293 // ss = seconds |
| 294 bool ParseStringToTimeSpan(const char* str, time64* time_span) { |
| 295 ASSERT(str); |
| 296 ASSERT(time_span); |
| 297 |
| 298 const char kColonDelimitor[] = ":"; |
| 299 const char kDotDelimitor = '.'; |
| 300 |
| 301 std::string str_span(str); |
| 302 time64 span = 0; |
| 303 |
| 304 int idx = str_span.find(kDotDelimitor); |
| 305 if (idx != -1) { |
| 306 std::string str_day = str_span.substr(0, idx); |
| 307 int day = 0; |
| 308 if (!ParseStringToInt(str_day.c_str(), &day, true) || |
| 309 day < 0 || day > 365) { |
| 310 return false; |
| 311 } |
| 312 span = day; |
| 313 |
| 314 str_span = str_span.substr(idx + 1); |
| 315 } |
| 316 |
| 317 const char* str_curr = str_span.c_str(); |
| 318 std::string str_token; |
| 319 |
| 320 str_token = SplitOneStringToken(&str_curr, kColonDelimitor); |
| 321 if (str_token == "") { |
| 322 return false; |
| 323 } |
| 324 |
| 325 int hour = 0; |
| 326 if (!ParseStringToInt(str_token.c_str(), &hour, true) || |
| 327 hour < 0 || hour > 23) { |
| 328 return false; |
| 329 } |
| 330 span = span * 24 + hour; |
| 331 |
| 332 str_token = SplitOneStringToken(&str_curr, kColonDelimitor); |
| 333 if (str_token == "") { |
| 334 return false; |
| 335 } |
| 336 |
| 337 int minute = 0; |
| 338 if (!ParseStringToInt(str_token.c_str(), &minute, true) || |
| 339 minute < 0 || minute > 59) { |
| 340 return false; |
| 341 } |
| 342 span = span * 60 + minute; |
| 343 |
| 344 str_token = SplitOneStringToken(&str_curr, kColonDelimitor); |
| 345 if (str_token == "") { |
| 346 return false; |
| 347 } |
| 348 |
| 349 int second = 0; |
| 350 if (!ParseStringToInt(str_token.c_str(), &second, true) || |
| 351 second < 0 || second > 59) { |
| 352 return false; |
| 353 } |
| 354 |
| 355 *time_span = (span * 60 + second) * kSecsTo100ns; |
| 356 |
| 357 return true; |
| 358 } |
| 359 |
| 360 } // namespace notifier |
OLD | NEW |