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