civil_time.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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 "y_absl/time/civil_time.h"
  15. #include <cstdlib>
  16. #include <ostream>
  17. #include <util/generic/string.h>
  18. #include "y_absl/strings/str_cat.h"
  19. #include "y_absl/time/time.h"
  20. namespace y_absl {
  21. Y_ABSL_NAMESPACE_BEGIN
  22. namespace {
  23. // Since a civil time has a larger year range than y_absl::Time (64-bit years vs
  24. // 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
  25. // around the year 2400, which will produce an equivalent year in a range that
  26. // y_absl::Time can handle.
  27. inline civil_year_t NormalizeYear(civil_year_t year) {
  28. return 2400 + year % 400;
  29. }
  30. // Formats the given CivilSecond according to the given format.
  31. TString FormatYearAnd(string_view fmt, CivilSecond cs) {
  32. const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
  33. cs.hour(), cs.minute(), cs.second());
  34. const TimeZone utc = UTCTimeZone();
  35. return StrCat(cs.year(), FormatTime(fmt, FromCivil(ncs, utc), utc));
  36. }
  37. template <typename CivilT>
  38. bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
  39. // Civil times support a larger year range than y_absl::Time, so we need to
  40. // parse the year separately, normalize it, then use y_absl::ParseTime on the
  41. // normalized string.
  42. const TString ss = TString(s); // TODO(y_absl-team): Avoid conversion.
  43. const char* const np = ss.c_str();
  44. char* endp;
  45. errno = 0;
  46. const civil_year_t y =
  47. std::strtoll(np, &endp, 10); // NOLINT(runtime/deprecated_fn)
  48. if (endp == np || errno == ERANGE) return false;
  49. const TString norm = StrCat(NormalizeYear(y), endp);
  50. const TimeZone utc = UTCTimeZone();
  51. Time t;
  52. if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
  53. const auto cs = ToCivilSecond(t, utc);
  54. *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
  55. return true;
  56. }
  57. return false;
  58. }
  59. // Tries to parse the type as a CivilT1, but then assigns the result to the
  60. // argument of type CivilT2.
  61. template <typename CivilT1, typename CivilT2>
  62. bool ParseAs(string_view s, CivilT2* c) {
  63. CivilT1 t1;
  64. if (ParseCivilTime(s, &t1)) {
  65. *c = CivilT2(t1);
  66. return true;
  67. }
  68. return false;
  69. }
  70. template <typename CivilT>
  71. bool ParseLenient(string_view s, CivilT* c) {
  72. // A fastpath for when the given string data parses exactly into the given
  73. // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
  74. if (ParseCivilTime(s, c)) return true;
  75. // Try parsing as each of the 6 types, trying the most common types first
  76. // (based on csearch results).
  77. if (ParseAs<CivilDay>(s, c)) return true;
  78. if (ParseAs<CivilSecond>(s, c)) return true;
  79. if (ParseAs<CivilHour>(s, c)) return true;
  80. if (ParseAs<CivilMonth>(s, c)) return true;
  81. if (ParseAs<CivilMinute>(s, c)) return true;
  82. if (ParseAs<CivilYear>(s, c)) return true;
  83. return false;
  84. }
  85. } // namespace
  86. TString FormatCivilTime(CivilSecond c) {
  87. return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
  88. }
  89. TString FormatCivilTime(CivilMinute c) {
  90. return FormatYearAnd("-%m-%d%ET%H:%M", c);
  91. }
  92. TString FormatCivilTime(CivilHour c) {
  93. return FormatYearAnd("-%m-%d%ET%H", c);
  94. }
  95. TString FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
  96. TString FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
  97. TString FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
  98. bool ParseCivilTime(string_view s, CivilSecond* c) {
  99. return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
  100. }
  101. bool ParseCivilTime(string_view s, CivilMinute* c) {
  102. return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
  103. }
  104. bool ParseCivilTime(string_view s, CivilHour* c) {
  105. return ParseYearAnd("-%m-%d%ET%H", s, c);
  106. }
  107. bool ParseCivilTime(string_view s, CivilDay* c) {
  108. return ParseYearAnd("-%m-%d", s, c);
  109. }
  110. bool ParseCivilTime(string_view s, CivilMonth* c) {
  111. return ParseYearAnd("-%m", s, c);
  112. }
  113. bool ParseCivilTime(string_view s, CivilYear* c) {
  114. return ParseYearAnd("", s, c);
  115. }
  116. bool ParseLenientCivilTime(string_view s, CivilSecond* c) {
  117. return ParseLenient(s, c);
  118. }
  119. bool ParseLenientCivilTime(string_view s, CivilMinute* c) {
  120. return ParseLenient(s, c);
  121. }
  122. bool ParseLenientCivilTime(string_view s, CivilHour* c) {
  123. return ParseLenient(s, c);
  124. }
  125. bool ParseLenientCivilTime(string_view s, CivilDay* c) {
  126. return ParseLenient(s, c);
  127. }
  128. bool ParseLenientCivilTime(string_view s, CivilMonth* c) {
  129. return ParseLenient(s, c);
  130. }
  131. bool ParseLenientCivilTime(string_view s, CivilYear* c) {
  132. return ParseLenient(s, c);
  133. }
  134. namespace time_internal {
  135. std::ostream& operator<<(std::ostream& os, CivilYear y) {
  136. return os << FormatCivilTime(y);
  137. }
  138. std::ostream& operator<<(std::ostream& os, CivilMonth m) {
  139. return os << FormatCivilTime(m);
  140. }
  141. std::ostream& operator<<(std::ostream& os, CivilDay d) {
  142. return os << FormatCivilTime(d);
  143. }
  144. std::ostream& operator<<(std::ostream& os, CivilHour h) {
  145. return os << FormatCivilTime(h);
  146. }
  147. std::ostream& operator<<(std::ostream& os, CivilMinute m) {
  148. return os << FormatCivilTime(m);
  149. }
  150. std::ostream& operator<<(std::ostream& os, CivilSecond s) {
  151. return os << FormatCivilTime(s);
  152. }
  153. bool AbslParseFlag(string_view s, CivilSecond* c, TString*) {
  154. return ParseLenientCivilTime(s, c);
  155. }
  156. bool AbslParseFlag(string_view s, CivilMinute* c, TString*) {
  157. return ParseLenientCivilTime(s, c);
  158. }
  159. bool AbslParseFlag(string_view s, CivilHour* c, TString*) {
  160. return ParseLenientCivilTime(s, c);
  161. }
  162. bool AbslParseFlag(string_view s, CivilDay* c, TString*) {
  163. return ParseLenientCivilTime(s, c);
  164. }
  165. bool AbslParseFlag(string_view s, CivilMonth* c, TString*) {
  166. return ParseLenientCivilTime(s, c);
  167. }
  168. bool AbslParseFlag(string_view s, CivilYear* c, TString*) {
  169. return ParseLenientCivilTime(s, c);
  170. }
  171. TString AbslUnparseFlag(CivilSecond c) { return FormatCivilTime(c); }
  172. TString AbslUnparseFlag(CivilMinute c) { return FormatCivilTime(c); }
  173. TString AbslUnparseFlag(CivilHour c) { return FormatCivilTime(c); }
  174. TString AbslUnparseFlag(CivilDay c) { return FormatCivilTime(c); }
  175. TString AbslUnparseFlag(CivilMonth c) { return FormatCivilTime(c); }
  176. TString AbslUnparseFlag(CivilYear c) { return FormatCivilTime(c); }
  177. } // namespace time_internal
  178. Y_ABSL_NAMESPACE_END
  179. } // namespace y_absl