1 // Copyright 2016 Google Inc. All Rights Reserved.
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 #if !defined(HAS_STRPTIME)
16 #if !defined(_MSC_VER) && !defined(__MINGW32__)
17 #define HAS_STRPTIME 1  // assume everyone has strptime() except windows
18 #endif
19 #endif
20 
21 #if defined(HAS_STRPTIME) && HAS_STRPTIME
22 #if !defined(_XOPEN_SOURCE)
23 #define _XOPEN_SOURCE  // Definedness suffices for strptime.
24 #endif
25 #endif
26 
27 #include "absl/base/config.h"
28 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
29 
30 // Include time.h directly since, by C++ standards, ctime doesn't have to
31 // declare strptime.
32 #include <time.h>
33 
34 #include <cctype>
35 #include <chrono>
36 #include <cstddef>
37 #include <cstdint>
38 #include <cstring>
39 #include <ctime>
40 #include <limits>
41 #include <string>
42 #include <vector>
43 #if !HAS_STRPTIME
44 #include <iomanip>
45 #include <sstream>
46 #endif
47 
48 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
49 #include "time_zone_if.h"
50 
51 namespace absl {
52 ABSL_NAMESPACE_BEGIN
53 namespace time_internal {
54 namespace cctz {
55 namespace detail {
56 
57 namespace {
58 
59 #if !HAS_STRPTIME
60 // Build a strptime() using C++11's std::get_time().
strptime(const char * s,const char * fmt,std::tm * tm)61 char* strptime(const char* s, const char* fmt, std::tm* tm) {
62   std::istringstream input(s);
63   input >> std::get_time(tm, fmt);
64   if (input.fail()) return nullptr;
65   return const_cast<char*>(s) +
66          (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
67 }
68 #endif
69 
ToTM(const time_zone::absolute_lookup & al)70 std::tm ToTM(const time_zone::absolute_lookup& al) {
71   std::tm tm{};
72   tm.tm_sec = al.cs.second();
73   tm.tm_min = al.cs.minute();
74   tm.tm_hour = al.cs.hour();
75   tm.tm_mday = al.cs.day();
76   tm.tm_mon = al.cs.month() - 1;
77 
78   // Saturate tm.tm_year is cases of over/underflow.
79   if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
80     tm.tm_year = std::numeric_limits<int>::min();
81   } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
82     tm.tm_year = std::numeric_limits<int>::max();
83   } else {
84     tm.tm_year = static_cast<int>(al.cs.year() - 1900);
85   }
86 
87   switch (get_weekday(al.cs)) {
88     case weekday::sunday:
89       tm.tm_wday = 0;
90       break;
91     case weekday::monday:
92       tm.tm_wday = 1;
93       break;
94     case weekday::tuesday:
95       tm.tm_wday = 2;
96       break;
97     case weekday::wednesday:
98       tm.tm_wday = 3;
99       break;
100     case weekday::thursday:
101       tm.tm_wday = 4;
102       break;
103     case weekday::friday:
104       tm.tm_wday = 5;
105       break;
106     case weekday::saturday:
107       tm.tm_wday = 6;
108       break;
109   }
110   tm.tm_yday = get_yearday(al.cs) - 1;
111   tm.tm_isdst = al.is_dst ? 1 : 0;
112   return tm;
113 }
114 
115 const char kDigits[] = "0123456789";
116 
117 // Formats a 64-bit integer in the given field width.  Note that it is up
118 // to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
119 // that there is sufficient space before ep to hold the conversion.
Format64(char * ep,int width,std::int_fast64_t v)120 char* Format64(char* ep, int width, std::int_fast64_t v) {
121   bool neg = false;
122   if (v < 0) {
123     --width;
124     neg = true;
125     if (v == std::numeric_limits<std::int_fast64_t>::min()) {
126       // Avoid negating minimum value.
127       std::int_fast64_t last_digit = -(v % 10);
128       v /= 10;
129       if (last_digit < 0) {
130         ++v;
131         last_digit += 10;
132       }
133       --width;
134       *--ep = kDigits[last_digit];
135     }
136     v = -v;
137   }
138   do {
139     --width;
140     *--ep = kDigits[v % 10];
141   } while (v /= 10);
142   while (--width >= 0) *--ep = '0';  // zero pad
143   if (neg) *--ep = '-';
144   return ep;
145 }
146 
147 // Formats [0 .. 99] as %02d.
Format02d(char * ep,int v)148 char* Format02d(char* ep, int v) {
149   *--ep = kDigits[v % 10];
150   *--ep = kDigits[(v / 10) % 10];
151   return ep;
152 }
153 
154 // Formats a UTC offset, like +00:00.
FormatOffset(char * ep,int offset,const char * mode)155 char* FormatOffset(char* ep, int offset, const char* mode) {
156   // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
157   // generate a "negative zero" when we're formatting a zero offset
158   // as the result of a failed load_time_zone().
159   char sign = '+';
160   if (offset < 0) {
161     offset = -offset;  // bounded by 24h so no overflow
162     sign = '-';
163   }
164   const int seconds = offset % 60;
165   const int minutes = (offset /= 60) % 60;
166   const int hours = offset /= 60;
167   const char sep = mode[0];
168   const bool ext = (sep != '\0' && mode[1] == '*');
169   const bool ccc = (ext && mode[2] == ':');
170   if (ext && (!ccc || seconds != 0)) {
171     ep = Format02d(ep, seconds);
172     *--ep = sep;
173   } else {
174     // If we're not rendering seconds, sub-minute negative offsets
175     // should get a positive sign (e.g., offset=-10s => "+00:00").
176     if (hours == 0 && minutes == 0) sign = '+';
177   }
178   if (!ccc || minutes != 0 || seconds != 0) {
179     ep = Format02d(ep, minutes);
180     if (sep != '\0') *--ep = sep;
181   }
182   ep = Format02d(ep, hours);
183   *--ep = sign;
184   return ep;
185 }
186 
187 // Formats a std::tm using strftime(3).
FormatTM(std::string * out,const std::string & fmt,const std::tm & tm)188 void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
189   // strftime(3) returns the number of characters placed in the output
190   // array (which may be 0 characters).  It also returns 0 to indicate
191   // an error, like the array wasn't large enough.  To accommodate this,
192   // the following code grows the buffer size from 2x the format string
193   // length up to 32x.
194   for (std::size_t i = 2; i != 32; i *= 2) {
195     std::size_t buf_size = fmt.size() * i;
196     std::vector<char> buf(buf_size);
197     if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
198       out->append(&buf[0], len);
199       return;
200     }
201   }
202 }
203 
204 // Used for %E#S/%E#f specifiers and for data values in parse().
205 template <typename T>
ParseInt(const char * dp,int width,T min,T max,T * vp)206 const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
207   if (dp != nullptr) {
208     const T kmin = std::numeric_limits<T>::min();
209     bool erange = false;
210     bool neg = false;
211     T value = 0;
212     if (*dp == '-') {
213       neg = true;
214       if (width <= 0 || --width != 0) {
215         ++dp;
216       } else {
217         dp = nullptr;  // width was 1
218       }
219     }
220     if (const char* const bp = dp) {
221       while (const char* cp = strchr(kDigits, *dp)) {
222         int d = static_cast<int>(cp - kDigits);
223         if (d >= 10) break;
224         if (value < kmin / 10) {
225           erange = true;
226           break;
227         }
228         value *= 10;
229         if (value < kmin + d) {
230           erange = true;
231           break;
232         }
233         value -= d;
234         dp += 1;
235         if (width > 0 && --width == 0) break;
236       }
237       if (dp != bp && !erange && (neg || value != kmin)) {
238         if (!neg || value != 0) {
239           if (!neg) value = -value;  // make positive
240           if (min <= value && value <= max) {
241             *vp = value;
242           } else {
243             dp = nullptr;
244           }
245         } else {
246           dp = nullptr;
247         }
248       } else {
249         dp = nullptr;
250       }
251     }
252   }
253   return dp;
254 }
255 
256 // The number of base-10 digits that can be represented by a signed 64-bit
257 // integer.  That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
258 const int kDigits10_64 = 18;
259 
260 // 10^n for everything that can be represented by a signed 64-bit integer.
261 const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
262     1,
263     10,
264     100,
265     1000,
266     10000,
267     100000,
268     1000000,
269     10000000,
270     100000000,
271     1000000000,
272     10000000000,
273     100000000000,
274     1000000000000,
275     10000000000000,
276     100000000000000,
277     1000000000000000,
278     10000000000000000,
279     100000000000000000,
280     1000000000000000000,
281 };
282 
283 }  // namespace
284 
285 // Uses strftime(3) to format the given Time.  The following extended format
286 // specifiers are also supported:
287 //
288 //   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
289 //   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
290 //   - %E#S - Seconds with # digits of fractional precision
291 //   - %E*S - Seconds with full fractional precision (a literal '*')
292 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
293 //
294 // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
295 // handled internally for performance reasons.  strftime(3) is slow due to
296 // a POSIX requirement to respect changes to ${TZ}.
297 //
298 // The TZ/GNU %s extension is handled internally because strftime() has
299 // to use mktime() to generate it, and that assumes the local time zone.
300 //
301 // We also handle the %z and %Z specifiers to accommodate platforms that do
302 // not support the tm_gmtoff and tm_zone extensions to std::tm.
303 //
304 // Requires that zero() <= fs < seconds(1).
format(const std::string & format,const time_point<seconds> & tp,const detail::femtoseconds & fs,const time_zone & tz)305 std::string format(const std::string& format, const time_point<seconds>& tp,
306                    const detail::femtoseconds& fs, const time_zone& tz) {
307   std::string result;
308   result.reserve(format.size());  // A reasonable guess for the result size.
309   const time_zone::absolute_lookup al = tz.lookup(tp);
310   const std::tm tm = ToTM(al);
311 
312   // Scratch buffer for internal conversions.
313   char buf[3 + kDigits10_64];  // enough for longest conversion
314   char* const ep = buf + sizeof(buf);
315   char* bp;  // works back from ep
316 
317   // Maintain three, disjoint subsequences that span format.
318   //   [format.begin() ... pending) : already formatted into result
319   //   [pending ... cur) : formatting pending, but no special cases
320   //   [cur ... format.end()) : unexamined
321   // Initially, everything is in the unexamined part.
322   const char* pending = format.c_str();  // NUL terminated
323   const char* cur = pending;
324   const char* end = pending + format.length();
325 
326   while (cur != end) {  // while something is unexamined
327     // Moves cur to the next percent sign.
328     const char* start = cur;
329     while (cur != end && *cur != '%') ++cur;
330 
331     // If the new pending text is all ordinary, copy it out.
332     if (cur != start && pending == start) {
333       result.append(pending, static_cast<std::size_t>(cur - pending));
334       pending = start = cur;
335     }
336 
337     // Span the sequential percent signs.
338     const char* percent = cur;
339     while (cur != end && *cur == '%') ++cur;
340 
341     // If the new pending text is all percents, copy out one
342     // percent for every matched pair, then skip those pairs.
343     if (cur != start && pending == start) {
344       std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
345       result.append(pending, escaped);
346       pending += escaped * 2;
347       // Also copy out a single trailing percent.
348       if (pending != cur && cur == end) {
349         result.push_back(*pending++);
350       }
351     }
352 
353     // Loop unless we have an unescaped percent.
354     if (cur == end || (cur - percent) % 2 == 0) continue;
355 
356     // Simple specifiers that we handle ourselves.
357     if (strchr("YmdeHMSzZs%", *cur)) {
358       if (cur - 1 != pending) {
359         FormatTM(&result, std::string(pending, cur - 1), tm);
360       }
361       switch (*cur) {
362         case 'Y':
363           // This avoids the tm.tm_year overflow problem for %Y, however
364           // tm.tm_year will still be used by other specifiers like %D.
365           bp = Format64(ep, 0, al.cs.year());
366           result.append(bp, static_cast<std::size_t>(ep - bp));
367           break;
368         case 'm':
369           bp = Format02d(ep, al.cs.month());
370           result.append(bp, static_cast<std::size_t>(ep - bp));
371           break;
372         case 'd':
373         case 'e':
374           bp = Format02d(ep, al.cs.day());
375           if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
376           result.append(bp, static_cast<std::size_t>(ep - bp));
377           break;
378         case 'H':
379           bp = Format02d(ep, al.cs.hour());
380           result.append(bp, static_cast<std::size_t>(ep - bp));
381           break;
382         case 'M':
383           bp = Format02d(ep, al.cs.minute());
384           result.append(bp, static_cast<std::size_t>(ep - bp));
385           break;
386         case 'S':
387           bp = Format02d(ep, al.cs.second());
388           result.append(bp, static_cast<std::size_t>(ep - bp));
389           break;
390         case 'z':
391           bp = FormatOffset(ep, al.offset, "");
392           result.append(bp, static_cast<std::size_t>(ep - bp));
393           break;
394         case 'Z':
395           result.append(al.abbr);
396           break;
397         case 's':
398           bp = Format64(ep, 0, ToUnixSeconds(tp));
399           result.append(bp, static_cast<std::size_t>(ep - bp));
400           break;
401         case '%':
402           result.push_back('%');
403           break;
404       }
405       pending = ++cur;
406       continue;
407     }
408 
409     // More complex specifiers that we handle ourselves.
410     if (*cur == ':' && cur + 1 != end) {
411       if (*(cur + 1) == 'z') {
412         // Formats %:z.
413         if (cur - 1 != pending) {
414           FormatTM(&result, std::string(pending, cur - 1), tm);
415         }
416         bp = FormatOffset(ep, al.offset, ":");
417         result.append(bp, static_cast<std::size_t>(ep - bp));
418         pending = cur += 2;
419         continue;
420       }
421       if (*(cur + 1) == ':' && cur + 2 != end) {
422         if (*(cur + 2) == 'z') {
423           // Formats %::z.
424           if (cur - 1 != pending) {
425             FormatTM(&result, std::string(pending, cur - 1), tm);
426           }
427           bp = FormatOffset(ep, al.offset, ":*");
428           result.append(bp, static_cast<std::size_t>(ep - bp));
429           pending = cur += 3;
430           continue;
431         }
432         if (*(cur + 2) == ':' && cur + 3 != end) {
433           if (*(cur + 3) == 'z') {
434             // Formats %:::z.
435             if (cur - 1 != pending) {
436               FormatTM(&result, std::string(pending, cur - 1), tm);
437             }
438             bp = FormatOffset(ep, al.offset, ":*:");
439             result.append(bp, static_cast<std::size_t>(ep - bp));
440             pending = cur += 4;
441             continue;
442           }
443         }
444       }
445     }
446 
447     // Loop if there is no E modifier.
448     if (*cur != 'E' || ++cur == end) continue;
449 
450     // Format our extensions.
451     if (*cur == 'z') {
452       // Formats %Ez.
453       if (cur - 2 != pending) {
454         FormatTM(&result, std::string(pending, cur - 2), tm);
455       }
456       bp = FormatOffset(ep, al.offset, ":");
457       result.append(bp, static_cast<std::size_t>(ep - bp));
458       pending = ++cur;
459     } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
460       // Formats %E*z.
461       if (cur - 2 != pending) {
462         FormatTM(&result, std::string(pending, cur - 2), tm);
463       }
464       bp = FormatOffset(ep, al.offset, ":*");
465       result.append(bp, static_cast<std::size_t>(ep - bp));
466       pending = cur += 2;
467     } else if (*cur == '*' && cur + 1 != end &&
468                (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
469       // Formats %E*S or %E*F.
470       if (cur - 2 != pending) {
471         FormatTM(&result, std::string(pending, cur - 2), tm);
472       }
473       char* cp = ep;
474       bp = Format64(cp, 15, fs.count());
475       while (cp != bp && cp[-1] == '0') --cp;
476       switch (*(cur + 1)) {
477         case 'S':
478           if (cp != bp) *--bp = '.';
479           bp = Format02d(bp, al.cs.second());
480           break;
481         case 'f':
482           if (cp == bp) *--bp = '0';
483           break;
484       }
485       result.append(bp, static_cast<std::size_t>(cp - bp));
486       pending = cur += 2;
487     } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
488       // Formats %E4Y.
489       if (cur - 2 != pending) {
490         FormatTM(&result, std::string(pending, cur - 2), tm);
491       }
492       bp = Format64(ep, 4, al.cs.year());
493       result.append(bp, static_cast<std::size_t>(ep - bp));
494       pending = cur += 2;
495     } else if (std::isdigit(*cur)) {
496       // Possibly found %E#S or %E#f.
497       int n = 0;
498       if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
499         if (*np == 'S' || *np == 'f') {
500           // Formats %E#S or %E#f.
501           if (cur - 2 != pending) {
502             FormatTM(&result, std::string(pending, cur - 2), tm);
503           }
504           bp = ep;
505           if (n > 0) {
506             if (n > kDigits10_64) n = kDigits10_64;
507             bp = Format64(bp, n,
508                           (n > 15) ? fs.count() * kExp10[n - 15]
509                                    : fs.count() / kExp10[15 - n]);
510             if (*np == 'S') *--bp = '.';
511           }
512           if (*np == 'S') bp = Format02d(bp, al.cs.second());
513           result.append(bp, static_cast<std::size_t>(ep - bp));
514           pending = cur = ++np;
515         }
516       }
517     }
518   }
519 
520   // Formats any remaining data.
521   if (end != pending) {
522     FormatTM(&result, std::string(pending, end), tm);
523   }
524 
525   return result;
526 }
527 
528 namespace {
529 
ParseOffset(const char * dp,const char * mode,int * offset)530 const char* ParseOffset(const char* dp, const char* mode, int* offset) {
531   if (dp != nullptr) {
532     const char first = *dp++;
533     if (first == '+' || first == '-') {
534       char sep = mode[0];
535       int hours = 0;
536       int minutes = 0;
537       int seconds = 0;
538       const char* ap = ParseInt(dp, 2, 0, 23, &hours);
539       if (ap != nullptr && ap - dp == 2) {
540         dp = ap;
541         if (sep != '\0' && *ap == sep) ++ap;
542         const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
543         if (bp != nullptr && bp - ap == 2) {
544           dp = bp;
545           if (sep != '\0' && *bp == sep) ++bp;
546           const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
547           if (cp != nullptr && cp - bp == 2) dp = cp;
548         }
549         *offset = ((hours * 60 + minutes) * 60) + seconds;
550         if (first == '-') *offset = -*offset;
551       } else {
552         dp = nullptr;
553       }
554     } else if (first == 'Z') {  // Zulu
555       *offset = 0;
556     } else {
557       dp = nullptr;
558     }
559   }
560   return dp;
561 }
562 
ParseZone(const char * dp,std::string * zone)563 const char* ParseZone(const char* dp, std::string* zone) {
564   zone->clear();
565   if (dp != nullptr) {
566     while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
567     if (zone->empty()) dp = nullptr;
568   }
569   return dp;
570 }
571 
ParseSubSeconds(const char * dp,detail::femtoseconds * subseconds)572 const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
573   if (dp != nullptr) {
574     std::int_fast64_t v = 0;
575     std::int_fast64_t exp = 0;
576     const char* const bp = dp;
577     while (const char* cp = strchr(kDigits, *dp)) {
578       int d = static_cast<int>(cp - kDigits);
579       if (d >= 10) break;
580       if (exp < 15) {
581         exp += 1;
582         v *= 10;
583         v += d;
584       }
585       ++dp;
586     }
587     if (dp != bp) {
588       v *= kExp10[15 - exp];
589       *subseconds = detail::femtoseconds(v);
590     } else {
591       dp = nullptr;
592     }
593   }
594   return dp;
595 }
596 
597 // Parses a string into a std::tm using strptime(3).
ParseTM(const char * dp,const char * fmt,std::tm * tm)598 const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
599   if (dp != nullptr) {
600     dp = strptime(dp, fmt, tm);
601   }
602   return dp;
603 }
604 
605 }  // namespace
606 
607 // Uses strptime(3) to parse the given input.  Supports the same extended
608 // format specifiers as format(), although %E#S and %E*S are treated
609 // identically (and similarly for %E#f and %E*f).  %Ez and %E*z also accept
610 // the same inputs.
611 //
612 // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
613 // handled internally so that we can normally avoid strptime() altogether
614 // (which is particularly helpful when the native implementation is broken).
615 //
616 // The TZ/GNU %s extension is handled internally because strptime() has to
617 // use localtime_r() to generate it, and that assumes the local time zone.
618 //
619 // We also handle the %z specifier to accommodate platforms that do not
620 // support the tm_gmtoff extension to std::tm.  %Z is parsed but ignored.
parse(const std::string & format,const std::string & input,const time_zone & tz,time_point<seconds> * sec,detail::femtoseconds * fs,std::string * err)621 bool parse(const std::string& format, const std::string& input,
622            const time_zone& tz, time_point<seconds>* sec,
623            detail::femtoseconds* fs, std::string* err) {
624   // The unparsed input.
625   const char* data = input.c_str();  // NUL terminated
626 
627   // Skips leading whitespace.
628   while (std::isspace(*data)) ++data;
629 
630   const year_t kyearmax = std::numeric_limits<year_t>::max();
631   const year_t kyearmin = std::numeric_limits<year_t>::min();
632 
633   // Sets default values for unspecified fields.
634   bool saw_year = false;
635   year_t year = 1970;
636   std::tm tm{};
637   tm.tm_year = 1970 - 1900;
638   tm.tm_mon = 1 - 1;  // Jan
639   tm.tm_mday = 1;
640   tm.tm_hour = 0;
641   tm.tm_min = 0;
642   tm.tm_sec = 0;
643   tm.tm_wday = 4;  // Thu
644   tm.tm_yday = 0;
645   tm.tm_isdst = 0;
646   auto subseconds = detail::femtoseconds::zero();
647   bool saw_offset = false;
648   int offset = 0;  // No offset from passed tz.
649   std::string zone = "UTC";
650 
651   const char* fmt = format.c_str();  // NUL terminated
652   bool twelve_hour = false;
653   bool afternoon = false;
654 
655   bool saw_percent_s = false;
656   std::int_fast64_t percent_s = 0;
657 
658   // Steps through format, one specifier at a time.
659   while (data != nullptr && *fmt != '\0') {
660     if (std::isspace(*fmt)) {
661       while (std::isspace(*data)) ++data;
662       while (std::isspace(*++fmt)) continue;
663       continue;
664     }
665 
666     if (*fmt != '%') {
667       if (*data == *fmt) {
668         ++data;
669         ++fmt;
670       } else {
671         data = nullptr;
672       }
673       continue;
674     }
675 
676     const char* percent = fmt;
677     if (*++fmt == '\0') {
678       data = nullptr;
679       continue;
680     }
681     switch (*fmt++) {
682       case 'Y':
683         // Symmetrically with FormatTime(), directly handing %Y avoids the
684         // tm.tm_year overflow problem.  However, tm.tm_year will still be
685         // used by other specifiers like %D.
686         data = ParseInt(data, 0, kyearmin, kyearmax, &year);
687         if (data != nullptr) saw_year = true;
688         continue;
689       case 'm':
690         data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
691         if (data != nullptr) tm.tm_mon -= 1;
692         continue;
693       case 'd':
694       case 'e':
695         data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
696         continue;
697       case 'H':
698         data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
699         twelve_hour = false;
700         continue;
701       case 'M':
702         data = ParseInt(data, 2, 0, 59, &tm.tm_min);
703         continue;
704       case 'S':
705         data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
706         continue;
707       case 'I':
708       case 'l':
709       case 'r':  // probably uses %I
710         twelve_hour = true;
711         break;
712       case 'R':  // uses %H
713       case 'T':  // uses %H
714       case 'c':  // probably uses %H
715       case 'X':  // probably uses %H
716         twelve_hour = false;
717         break;
718       case 'z':
719         data = ParseOffset(data, "", &offset);
720         if (data != nullptr) saw_offset = true;
721         continue;
722       case 'Z':  // ignored; zone abbreviations are ambiguous
723         data = ParseZone(data, &zone);
724         continue;
725       case 's':
726         data =
727             ParseInt(data, 0, std::numeric_limits<std::int_fast64_t>::min(),
728                      std::numeric_limits<std::int_fast64_t>::max(), &percent_s);
729         if (data != nullptr) saw_percent_s = true;
730         continue;
731       case ':':
732         if (fmt[0] == 'z' ||
733             (fmt[0] == ':' &&
734              (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
735           data = ParseOffset(data, ":", &offset);
736           if (data != nullptr) saw_offset = true;
737           fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
738           continue;
739         }
740         break;
741       case '%':
742         data = (*data == '%' ? data + 1 : nullptr);
743         continue;
744       case 'E':
745         if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
746           data = ParseOffset(data, ":", &offset);
747           if (data != nullptr) saw_offset = true;
748           fmt += (fmt[0] == 'z') ? 1 : 2;
749           continue;
750         }
751         if (fmt[0] == '*' && fmt[1] == 'S') {
752           data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
753           if (data != nullptr && *data == '.') {
754             data = ParseSubSeconds(data + 1, &subseconds);
755           }
756           fmt += 2;
757           continue;
758         }
759         if (fmt[0] == '*' && fmt[1] == 'f') {
760           if (data != nullptr && std::isdigit(*data)) {
761             data = ParseSubSeconds(data, &subseconds);
762           }
763           fmt += 2;
764           continue;
765         }
766         if (fmt[0] == '4' && fmt[1] == 'Y') {
767           const char* bp = data;
768           data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
769           if (data != nullptr) {
770             if (data - bp == 4) {
771               saw_year = true;
772             } else {
773               data = nullptr;  // stopped too soon
774             }
775           }
776           fmt += 2;
777           continue;
778         }
779         if (std::isdigit(*fmt)) {
780           int n = 0;  // value ignored
781           if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
782             if (*np == 'S') {
783               data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
784               if (data != nullptr && *data == '.') {
785                 data = ParseSubSeconds(data + 1, &subseconds);
786               }
787               fmt = ++np;
788               continue;
789             }
790             if (*np == 'f') {
791               if (data != nullptr && std::isdigit(*data)) {
792                 data = ParseSubSeconds(data, &subseconds);
793               }
794               fmt = ++np;
795               continue;
796             }
797           }
798         }
799         if (*fmt == 'c') twelve_hour = false;  // probably uses %H
800         if (*fmt == 'X') twelve_hour = false;  // probably uses %H
801         if (*fmt != '\0') ++fmt;
802         break;
803       case 'O':
804         if (*fmt == 'H') twelve_hour = false;
805         if (*fmt == 'I') twelve_hour = true;
806         if (*fmt != '\0') ++fmt;
807         break;
808     }
809 
810     // Parses the current specifier.
811     const char* orig_data = data;
812     std::string spec(percent, static_cast<std::size_t>(fmt - percent));
813     data = ParseTM(data, spec.c_str(), &tm);
814 
815     // If we successfully parsed %p we need to remember whether the result
816     // was AM or PM so that we can adjust tm_hour before time_zone::lookup().
817     // So reparse the input with a known AM hour, and check if it is shifted
818     // to a PM hour.
819     if (spec == "%p" && data != nullptr) {
820       std::string test_input = "1";
821       test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
822       const char* test_data = test_input.c_str();
823       std::tm tmp{};
824       ParseTM(test_data, "%I%p", &tmp);
825       afternoon = (tmp.tm_hour == 13);
826     }
827   }
828 
829   // Adjust a 12-hour tm_hour value if it should be in the afternoon.
830   if (twelve_hour && afternoon && tm.tm_hour < 12) {
831     tm.tm_hour += 12;
832   }
833 
834   if (data == nullptr) {
835     if (err != nullptr) *err = "Failed to parse input";
836     return false;
837   }
838 
839   // Skip any remaining whitespace.
840   while (std::isspace(*data)) ++data;
841 
842   // parse() must consume the entire input string.
843   if (*data != '\0') {
844     if (err != nullptr) *err = "Illegal trailing data in input string";
845     return false;
846   }
847 
848   // If we saw %s then we ignore anything else and return that time.
849   if (saw_percent_s) {
850     *sec = FromUnixSeconds(percent_s);
851     *fs = detail::femtoseconds::zero();
852     return true;
853   }
854 
855   // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
856   // in UTC and then shift by that offset.  Otherwise we want to interpret
857   // the fields directly in the passed time_zone.
858   time_zone ptz = saw_offset ? utc_time_zone() : tz;
859 
860   // Allows a leap second of 60 to normalize forward to the following ":00".
861   if (tm.tm_sec == 60) {
862     tm.tm_sec -= 1;
863     offset -= 1;
864     subseconds = detail::femtoseconds::zero();
865   }
866 
867   if (!saw_year) {
868     year = year_t{tm.tm_year};
869     if (year > kyearmax - 1900) {
870       // Platform-dependent, maybe unreachable.
871       if (err != nullptr) *err = "Out-of-range year";
872       return false;
873     }
874     year += 1900;
875   }
876 
877   const int month = tm.tm_mon + 1;
878   civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
879 
880   // parse() should not allow normalization. Due to the restricted field
881   // ranges above (see ParseInt()), the only possibility is for days to roll
882   // into months. That is, parsing "Sep 31" should not produce "Oct 1".
883   if (cs.month() != month || cs.day() != tm.tm_mday) {
884     if (err != nullptr) *err = "Out-of-range field";
885     return false;
886   }
887 
888   // Accounts for the offset adjustment before converting to absolute time.
889   if ((offset < 0 && cs > civil_second::max() + offset) ||
890       (offset > 0 && cs < civil_second::min() + offset)) {
891     if (err != nullptr) *err = "Out-of-range field";
892     return false;
893   }
894   cs -= offset;
895 
896   const auto tp = ptz.lookup(cs).pre;
897   // Checks for overflow/underflow and returns an error as necessary.
898   if (tp == time_point<seconds>::max()) {
899     const auto al = ptz.lookup(time_point<seconds>::max());
900     if (cs > al.cs) {
901       if (err != nullptr) *err = "Out-of-range field";
902       return false;
903     }
904   }
905   if (tp == time_point<seconds>::min()) {
906     const auto al = ptz.lookup(time_point<seconds>::min());
907     if (cs < al.cs) {
908       if (err != nullptr) *err = "Out-of-range field";
909       return false;
910     }
911   }
912 
913   *sec = tp;
914   *fs = subseconds;
915   return true;
916 }
917 
918 }  // namespace detail
919 }  // namespace cctz
920 }  // namespace time_internal
921 ABSL_NAMESPACE_END
922 }  // namespace absl
923