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