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