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