time_util.cc 6.0 KB

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