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