civil_time.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2018 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/time/civil_time.h"
  15. #include <cstdlib>
  16. #include <string>
  17. #include "absl/strings/str_cat.h"
  18. #include "absl/time/time.h"
  19. namespace absl {
  20. ABSL_NAMESPACE_BEGIN
  21. namespace {
  22. // Since a civil time has a larger year range than absl::Time (64-bit years vs
  23. // 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
  24. // around the year 2400, which will produce an equivalent year in a range that
  25. // absl::Time can handle.
  26. inline civil_year_t NormalizeYear(civil_year_t year) {
  27. return 2400 + year % 400;
  28. }
  29. // Formats the given CivilSecond according to the given format.
  30. std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
  31. const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
  32. cs.hour(), cs.minute(), cs.second());
  33. const TimeZone utc = UTCTimeZone();
  34. return StrCat(cs.year(), FormatTime(fmt, FromCivil(ncs, utc), utc));
  35. }
  36. template <typename CivilT>
  37. bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
  38. // Civil times support a larger year range than absl::Time, so we need to
  39. // parse the year separately, normalize it, then use absl::ParseTime on the
  40. // normalized string.
  41. const std::string ss = std::string(s); // TODO(absl-team): Avoid conversion.
  42. const char* const np = ss.c_str();
  43. char* endp;
  44. errno = 0;
  45. const civil_year_t y =
  46. std::strtoll(np, &endp, 10); // NOLINT(runtime/deprecated_fn)
  47. if (endp == np || errno == ERANGE) return false;
  48. const std::string norm = StrCat(NormalizeYear(y), endp);
  49. const TimeZone utc = UTCTimeZone();
  50. Time t;
  51. if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
  52. const auto cs = ToCivilSecond(t, utc);
  53. *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
  54. return true;
  55. }
  56. return false;
  57. }
  58. // Tries to parse the type as a CivilT1, but then assigns the result to the
  59. // argument of type CivilT2.
  60. template <typename CivilT1, typename CivilT2>
  61. bool ParseAs(string_view s, CivilT2* c) {
  62. CivilT1 t1;
  63. if (ParseCivilTime(s, &t1)) {
  64. *c = CivilT2(t1);
  65. return true;
  66. }
  67. return false;
  68. }
  69. template <typename CivilT>
  70. bool ParseLenient(string_view s, CivilT* c) {
  71. // A fastpath for when the given string data parses exactly into the given
  72. // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
  73. if (ParseCivilTime(s, c)) return true;
  74. // Try parsing as each of the 6 types, trying the most common types first
  75. // (based on csearch results).
  76. if (ParseAs<CivilDay>(s, c)) return true;
  77. if (ParseAs<CivilSecond>(s, c)) return true;
  78. if (ParseAs<CivilHour>(s, c)) return true;
  79. if (ParseAs<CivilMonth>(s, c)) return true;
  80. if (ParseAs<CivilMinute>(s, c)) return true;
  81. if (ParseAs<CivilYear>(s, c)) return true;
  82. return false;
  83. }
  84. } // namespace
  85. std::string FormatCivilTime(CivilSecond c) {
  86. return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
  87. }
  88. std::string FormatCivilTime(CivilMinute c) {
  89. return FormatYearAnd("-%m-%d%ET%H:%M", c);
  90. }
  91. std::string FormatCivilTime(CivilHour c) {
  92. return FormatYearAnd("-%m-%d%ET%H", c);
  93. }
  94. std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
  95. std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
  96. std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
  97. bool ParseCivilTime(string_view s, CivilSecond* c) {
  98. return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
  99. }
  100. bool ParseCivilTime(string_view s, CivilMinute* c) {
  101. return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
  102. }
  103. bool ParseCivilTime(string_view s, CivilHour* c) {
  104. return ParseYearAnd("-%m-%d%ET%H", s, c);
  105. }
  106. bool ParseCivilTime(string_view s, CivilDay* c) {
  107. return ParseYearAnd("-%m-%d", s, c);
  108. }
  109. bool ParseCivilTime(string_view s, CivilMonth* c) {
  110. return ParseYearAnd("-%m", s, c);
  111. }
  112. bool ParseCivilTime(string_view s, CivilYear* c) {
  113. return ParseYearAnd("", s, c);
  114. }
  115. bool ParseLenientCivilTime(string_view s, CivilSecond* c) {
  116. return ParseLenient(s, c);
  117. }
  118. bool ParseLenientCivilTime(string_view s, CivilMinute* c) {
  119. return ParseLenient(s, c);
  120. }
  121. bool ParseLenientCivilTime(string_view s, CivilHour* c) {
  122. return ParseLenient(s, c);
  123. }
  124. bool ParseLenientCivilTime(string_view s, CivilDay* c) {
  125. return ParseLenient(s, c);
  126. }
  127. bool ParseLenientCivilTime(string_view s, CivilMonth* c) {
  128. return ParseLenient(s, c);
  129. }
  130. bool ParseLenientCivilTime(string_view s, CivilYear* c) {
  131. return ParseLenient(s, c);
  132. }
  133. namespace time_internal {
  134. std::ostream& operator<<(std::ostream& os, CivilYear y) {
  135. return os << FormatCivilTime(y);
  136. }
  137. std::ostream& operator<<(std::ostream& os, CivilMonth m) {
  138. return os << FormatCivilTime(m);
  139. }
  140. std::ostream& operator<<(std::ostream& os, CivilDay d) {
  141. return os << FormatCivilTime(d);
  142. }
  143. std::ostream& operator<<(std::ostream& os, CivilHour h) {
  144. return os << FormatCivilTime(h);
  145. }
  146. std::ostream& operator<<(std::ostream& os, CivilMinute m) {
  147. return os << FormatCivilTime(m);
  148. }
  149. std::ostream& operator<<(std::ostream& os, CivilSecond s) {
  150. return os << FormatCivilTime(s);
  151. }
  152. } // namespace time_internal
  153. ABSL_NAMESPACE_END
  154. } // namespace absl