• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "google_apis/drive/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 
ParseTimezone(const base::StringPiece & timezone,bool ahead,int * out_offset_to_utc_in_minutes)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 
GetTimeFromString(const base::StringPiece & raw_value,base::Time * parsed_time)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 
FormatTimeAsString(const base::Time & time)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 
FormatTimeAsStringLocaltime(const base::Time & time)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