Add ICU message format support
[chromium-blink-merge.git] / google_apis / drive / time_util.cc
blobcf2b453d38c78708b67a99b2db7c5a858c26c5aa
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.
5 #include "google_apis/drive/time_util.h"
7 #include <string>
8 #include <vector>
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
16 namespace google_apis {
17 namespace util {
19 namespace {
21 const char kNullTimeString[] = "null";
23 bool ParseTimezone(const base::StringPiece& timezone,
24 bool ahead,
25 int* out_offset_to_utc_in_minutes) {
26 DCHECK(out_offset_to_utc_in_minutes);
28 std::vector<base::StringPiece> parts = base::SplitStringPiece(
29 timezone, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
31 int hour = 0;
32 if (parts.empty() || !base::StringToInt(parts[0], &hour))
33 return false;
35 int minute = 0;
36 if (parts.size() > 1 && !base::StringToInt(parts[1], &minute))
37 return false;
39 *out_offset_to_utc_in_minutes = (hour * 60 + minute) * (ahead ? +1 : -1);
40 return true;
43 } // namespace
45 bool GetTimeFromString(const base::StringPiece& raw_value,
46 base::Time* parsed_time) {
47 base::StringPiece date;
48 base::StringPiece time_and_tz;
49 base::StringPiece time;
50 base::Time::Exploded exploded = {0};
51 bool has_timezone = false;
52 int offset_to_utc_in_minutes = 0;
54 // Splits the string into "date" part and "time" part.
56 std::vector<base::StringPiece> parts = base::SplitStringPiece(
57 raw_value, "T", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
58 if (parts.size() != 2)
59 return false;
60 date = parts[0];
61 time_and_tz = parts[1];
64 // Parses timezone suffix on the time part if available.
66 std::vector<base::StringPiece> parts;
67 if (time_and_tz[time_and_tz.size() - 1] == 'Z') {
68 // Timezone is 'Z' (UTC)
69 has_timezone = true;
70 offset_to_utc_in_minutes = 0;
71 time = time_and_tz;
72 time.remove_suffix(1);
73 } else {
74 parts = base::SplitStringPiece(
75 time_and_tz, "+", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
76 if (parts.size() == 2) {
77 // Timezone is "+hh:mm" format
78 if (!ParseTimezone(parts[1], true, &offset_to_utc_in_minutes))
79 return false;
80 has_timezone = true;
81 time = parts[0];
82 } else {
83 parts = base::SplitStringPiece(
84 time_and_tz, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
85 if (parts.size() == 2) {
86 // Timezone is "-hh:mm" format
87 if (!ParseTimezone(parts[1], false, &offset_to_utc_in_minutes))
88 return false;
89 has_timezone = true;
90 time = parts[0];
91 } else {
92 // No timezone (uses local timezone)
93 time = time_and_tz;
99 // Parses the date part.
101 std::vector<base::StringPiece> parts = base::SplitStringPiece(
102 date, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
103 if (parts.size() != 3)
104 return false;
106 if (!base::StringToInt(parts[0], &exploded.year) ||
107 !base::StringToInt(parts[1], &exploded.month) ||
108 !base::StringToInt(parts[2], &exploded.day_of_month)) {
109 return false;
113 // Parses the time part.
115 std::vector<base::StringPiece> parts = base::SplitStringPiece(
116 time, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
117 if (parts.size() != 3)
118 return false;
120 if (!base::StringToInt(parts[0], &exploded.hour) ||
121 !base::StringToInt(parts[1], &exploded.minute)) {
122 return false;
125 std::vector<base::StringPiece> seconds_parts = base::SplitStringPiece(
126 parts[2], ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
127 if (seconds_parts.size() >= 3)
128 return false;
130 if (!base::StringToInt(seconds_parts[0], &exploded.second))
131 return false;
133 // Only accept milli-seconds (3-digits).
134 if (seconds_parts.size() > 1 &&
135 seconds_parts[1].length() == 3 &&
136 !base::StringToInt(seconds_parts[1], &exploded.millisecond)) {
137 return false;
141 exploded.day_of_week = 0;
142 if (!exploded.HasValidValues())
143 return false;
145 if (has_timezone) {
146 *parsed_time = base::Time::FromUTCExploded(exploded);
147 if (offset_to_utc_in_minutes != 0)
148 *parsed_time -= base::TimeDelta::FromMinutes(offset_to_utc_in_minutes);
149 } else {
150 *parsed_time = base::Time::FromLocalExploded(exploded);
153 return true;
156 std::string FormatTimeAsString(const base::Time& time) {
157 if (time.is_null())
158 return kNullTimeString;
160 base::Time::Exploded exploded;
161 time.UTCExplode(&exploded);
162 return base::StringPrintf(
163 "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ",
164 exploded.year, exploded.month, exploded.day_of_month,
165 exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
168 std::string FormatTimeAsStringLocaltime(const base::Time& time) {
169 if (time.is_null())
170 return kNullTimeString;
172 base::Time::Exploded exploded;
173 time.LocalExplode(&exploded);
174 return base::StringPrintf(
175 "%04d-%02d-%02dT%02d:%02d:%02d.%03d",
176 exploded.year, exploded.month, exploded.day_of_month,
177 exploded.hour, exploded.minute, exploded.second, exploded.millisecond);
180 } // namespace util
181 } // namespace google_apis