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