Home | History | Annotate | Download | only in google_apis
      1 // Copyright (c) 2012 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/google_apis/time_util.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/time/time.h"
     14 
     15 namespace google_apis {
     16 namespace util {
     17 
     18 namespace {
     19 
     20 const char kNullTimeString[] = "null";
     21 
     22 bool ParseTimezone(const base::StringPiece& timezone,
     23                    bool ahead,
     24                    int* out_offset_to_utc_in_minutes) {
     25   DCHECK(out_offset_to_utc_in_minutes);
     26 
     27   std::vector<base::StringPiece> parts;
     28   int num_of_token = Tokenize(timezone, ":", &parts);
     29 
     30   int hour = 0;
     31   if (!base::StringToInt(parts[0], &hour))
     32     return false;
     33 
     34   int minute = 0;
     35   if (num_of_token > 1 && !base::StringToInt(parts[1], &minute))
     36     return false;
     37 
     38   *out_offset_to_utc_in_minutes = (hour * 60 + minute) * (ahead ? +1 : -1);
     39   return true;
     40 }
     41 
     42 }  // namespace
     43 
     44 bool GetTimeFromString(const base::StringPiece& raw_value,
     45                        base::Time* parsed_time) {
     46   base::StringPiece date;
     47   base::StringPiece time_and_tz;
     48   base::StringPiece time;
     49   base::Time::Exploded exploded = {0};
     50   bool has_timezone = false;
     51   int offset_to_utc_in_minutes = 0;
     52 
     53   // Splits the string into "date" part and "time" part.
     54   {
     55     std::vector<base::StringPiece> parts;
     56     if (Tokenize(raw_value, "T", &parts) != 2)
     57       return false;
     58     date = parts[0];
     59     time_and_tz = parts[1];
     60   }
     61 
     62   // Parses timezone suffix on the time part if available.
     63   {
     64     std::vector<base::StringPiece> parts;
     65     if (time_and_tz[time_and_tz.size() - 1] == 'Z') {
     66       // Timezone is 'Z' (UTC)
     67       has_timezone = true;
     68       offset_to_utc_in_minutes = 0;
     69       time = time_and_tz;
     70       time.remove_suffix(1);
     71     } else if (Tokenize(time_and_tz, "+", &parts) == 2) {
     72       // Timezone is "+hh:mm" format
     73       if (!ParseTimezone(parts[1], true, &offset_to_utc_in_minutes))
     74         return false;
     75       has_timezone = true;
     76       time = parts[0];
     77     } else if (Tokenize(time_and_tz, "-", &parts) == 2) {
     78       // Timezone is "-hh:mm" format
     79       if (!ParseTimezone(parts[1], false, &offset_to_utc_in_minutes))
     80         return false;
     81       has_timezone = true;
     82       time = parts[0];
     83     } else {
     84       // No timezone (uses local timezone)
     85       time = time_and_tz;
     86     }
     87   }
     88 
     89   // Parses the date part.
     90   {
     91     std::vector<base::StringPiece> parts;
     92     if (Tokenize(date, "-", &parts) != 3)
     93       return false;
     94 
     95     if (!base::StringToInt(parts[0], &exploded.year) ||
     96         !base::StringToInt(parts[1], &exploded.month) ||
     97         !base::StringToInt(parts[2], &exploded.day_of_month)) {
     98       return false;
     99     }
    100   }
    101 
    102   // Parses the time part.
    103   {
    104     std::vector<base::StringPiece> parts;
    105     int num_of_token = Tokenize(time, ":", &parts);
    106     if (num_of_token != 3)
    107       return false;
    108 
    109     if (!base::StringToInt(parts[0], &exploded.hour) ||
    110         !base::StringToInt(parts[1], &exploded.minute)) {
    111       return false;
    112     }
    113 
    114     std::vector<base::StringPiece> seconds_parts;
    115     int num_of_seconds_token = Tokenize(parts[2], ".", &seconds_parts);
    116     if (num_of_seconds_token >= 3)
    117       return false;
    118 
    119     if (!base::StringToInt(seconds_parts[0], &exploded.second))
    120         return false;
    121 
    122     // Only accept milli-seconds (3-digits).
    123     if (num_of_seconds_token > 1 &&
    124         seconds_parts[1].length() == 3 &&
    125         !base::StringToInt(seconds_parts[1], &exploded.millisecond)) {
    126       return false;
    127     }
    128   }
    129 
    130   exploded.day_of_week = 0;
    131   if (!exploded.HasValidValues())
    132     return false;
    133 
    134   if (has_timezone) {
    135     *parsed_time = base::Time::FromUTCExploded(exploded);
    136     if (offset_to_utc_in_minutes != 0)
    137       *parsed_time -= base::TimeDelta::FromMinutes(offset_to_utc_in_minutes);
    138   } else {
    139     *parsed_time = base::Time::FromLocalExploded(exploded);
    140   }
    141 
    142   return true;
    143 }
    144 
    145 std::string FormatTimeAsString(const base::Time& time) {
    146   if (time.is_null())
    147     return kNullTimeString;
    148 
    149   base::Time::Exploded exploded;
    150   time.UTCExplode(&exploded);
    151   return base::StringPrintf(
    152       "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
    153       exploded.year, exploded.month, exploded.day_of_month,
    154       exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
    155 }
    156 
    157 std::string FormatTimeAsStringLocaltime(const base::Time& time) {
    158   if (time.is_null())
    159     return kNullTimeString;
    160 
    161   base::Time::Exploded exploded;
    162   time.LocalExplode(&exploded);
    163   return base::StringPrintf(
    164       "%04d-%02d-%02dT%02d:%02d:%02d.%03d",
    165       exploded.year, exploded.month, exploded.day_of_month,
    166       exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
    167 }
    168 
    169 }  // namespace util
    170 }  // namespace google_apis
    171