00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #if !defined(HAS_STRPTIME)
00016 # if !defined(_MSC_VER) && !defined(__MINGW32__)
00017 # define HAS_STRPTIME 1 // assume everyone has strptime() except windows
00018 # endif
00019 #endif
00020
00021 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
00022
00023 #include <cctype>
00024 #include <chrono>
00025 #include <cstddef>
00026 #include <cstdint>
00027 #include <cstring>
00028 #include <ctime>
00029 #include <limits>
00030 #include <string>
00031 #include <vector>
00032 #if !HAS_STRPTIME
00033 #include <iomanip>
00034 #include <sstream>
00035 #endif
00036
00037 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
00038 #include "time_zone_if.h"
00039
00040 namespace absl {
00041 namespace time_internal {
00042 namespace cctz {
00043 namespace detail {
00044
00045 namespace {
00046
00047 #if !HAS_STRPTIME
00048
00049 char* strptime(const char* s, const char* fmt, std::tm* tm) {
00050 std::istringstream input(s);
00051 input >> std::get_time(tm, fmt);
00052 if (input.fail()) return nullptr;
00053 return const_cast<char*>(s) +
00054 (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
00055 }
00056 #endif
00057
00058 std::tm ToTM(const time_zone::absolute_lookup& al) {
00059 std::tm tm{};
00060 tm.tm_sec = al.cs.second();
00061 tm.tm_min = al.cs.minute();
00062 tm.tm_hour = al.cs.hour();
00063 tm.tm_mday = al.cs.day();
00064 tm.tm_mon = al.cs.month() - 1;
00065
00066
00067 if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
00068 tm.tm_year = std::numeric_limits<int>::min();
00069 } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
00070 tm.tm_year = std::numeric_limits<int>::max();
00071 } else {
00072 tm.tm_year = static_cast<int>(al.cs.year() - 1900);
00073 }
00074
00075 switch (get_weekday(civil_day(al.cs))) {
00076 case weekday::sunday:
00077 tm.tm_wday = 0;
00078 break;
00079 case weekday::monday:
00080 tm.tm_wday = 1;
00081 break;
00082 case weekday::tuesday:
00083 tm.tm_wday = 2;
00084 break;
00085 case weekday::wednesday:
00086 tm.tm_wday = 3;
00087 break;
00088 case weekday::thursday:
00089 tm.tm_wday = 4;
00090 break;
00091 case weekday::friday:
00092 tm.tm_wday = 5;
00093 break;
00094 case weekday::saturday:
00095 tm.tm_wday = 6;
00096 break;
00097 }
00098 tm.tm_yday = get_yearday(civil_day(al.cs)) - 1;
00099 tm.tm_isdst = al.is_dst ? 1 : 0;
00100 return tm;
00101 }
00102
00103 const char kDigits[] = "0123456789";
00104
00105
00106
00107
00108 char* Format64(char* ep, int width, std::int_fast64_t v) {
00109 bool neg = false;
00110 if (v < 0) {
00111 --width;
00112 neg = true;
00113 if (v == std::numeric_limits<std::int_fast64_t>::min()) {
00114
00115 std::int_fast64_t last_digit = -(v % 10);
00116 v /= 10;
00117 if (last_digit < 0) {
00118 ++v;
00119 last_digit += 10;
00120 }
00121 --width;
00122 *--ep = kDigits[last_digit];
00123 }
00124 v = -v;
00125 }
00126 do {
00127 --width;
00128 *--ep = kDigits[v % 10];
00129 } while (v /= 10);
00130 while (--width >= 0) *--ep = '0';
00131 if (neg) *--ep = '-';
00132 return ep;
00133 }
00134
00135
00136 char* Format02d(char* ep, int v) {
00137 *--ep = kDigits[v % 10];
00138 *--ep = kDigits[(v / 10) % 10];
00139 return ep;
00140 }
00141
00142
00143 char* FormatOffset(char* ep, int offset, const char* mode) {
00144
00145
00146
00147 char sign = '+';
00148 if (offset < 0) {
00149 offset = -offset;
00150 sign = '-';
00151 }
00152 const int seconds = offset % 60;
00153 const int minutes = (offset /= 60) % 60;
00154 const int hours = offset /= 60;
00155 const char sep = mode[0];
00156 const bool ext = (sep != '\0' && mode[1] == '*');
00157 const bool ccc = (ext && mode[2] == ':');
00158 if (ext && (!ccc || seconds != 0)) {
00159 ep = Format02d(ep, seconds);
00160 *--ep = sep;
00161 } else {
00162
00163
00164 if (hours == 0 && minutes == 0) sign = '+';
00165 }
00166 if (!ccc || minutes != 0 || seconds != 0) {
00167 ep = Format02d(ep, minutes);
00168 if (sep != '\0') *--ep = sep;
00169 }
00170 ep = Format02d(ep, hours);
00171 *--ep = sign;
00172 return ep;
00173 }
00174
00175
00176 void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
00177
00178
00179
00180
00181
00182 for (std::size_t i = 2; i != 32; i *= 2) {
00183 std::size_t buf_size = fmt.size() * i;
00184 std::vector<char> buf(buf_size);
00185 if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
00186 out->append(&buf[0], len);
00187 return;
00188 }
00189 }
00190 }
00191
00192
00193 template <typename T>
00194 const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
00195 if (dp != nullptr) {
00196 const T kmin = std::numeric_limits<T>::min();
00197 bool erange = false;
00198 bool neg = false;
00199 T value = 0;
00200 if (*dp == '-') {
00201 neg = true;
00202 if (width <= 0 || --width != 0) {
00203 ++dp;
00204 } else {
00205 dp = nullptr;
00206 }
00207 }
00208 if (const char* const bp = dp) {
00209 while (const char* cp = strchr(kDigits, *dp)) {
00210 int d = static_cast<int>(cp - kDigits);
00211 if (d >= 10) break;
00212 if (value < kmin / 10) {
00213 erange = true;
00214 break;
00215 }
00216 value *= 10;
00217 if (value < kmin + d) {
00218 erange = true;
00219 break;
00220 }
00221 value -= d;
00222 dp += 1;
00223 if (width > 0 && --width == 0) break;
00224 }
00225 if (dp != bp && !erange && (neg || value != kmin)) {
00226 if (!neg || value != 0) {
00227 if (!neg) value = -value;
00228 if (min <= value && value <= max) {
00229 *vp = value;
00230 } else {
00231 dp = nullptr;
00232 }
00233 } else {
00234 dp = nullptr;
00235 }
00236 } else {
00237 dp = nullptr;
00238 }
00239 }
00240 }
00241 return dp;
00242 }
00243
00244
00245
00246 const int kDigits10_64 = 18;
00247
00248
00249 const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
00250 1,
00251 10,
00252 100,
00253 1000,
00254 10000,
00255 100000,
00256 1000000,
00257 10000000,
00258 100000000,
00259 1000000000,
00260 10000000000,
00261 100000000000,
00262 1000000000000,
00263 10000000000000,
00264 100000000000000,
00265 1000000000000000,
00266 10000000000000000,
00267 100000000000000000,
00268 1000000000000000000,
00269 };
00270
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 std::string format(const std::string& format, const time_point<seconds>& tp,
00294 const detail::femtoseconds& fs, const time_zone& tz) {
00295 std::string result;
00296 result.reserve(format.size());
00297 const time_zone::absolute_lookup al = tz.lookup(tp);
00298 const std::tm tm = ToTM(al);
00299
00300
00301 char buf[3 + kDigits10_64];
00302 char* const ep = buf + sizeof(buf);
00303 char* bp;
00304
00305
00306
00307
00308
00309
00310 const char* pending = format.c_str();
00311 const char* cur = pending;
00312 const char* end = pending + format.length();
00313
00314 while (cur != end) {
00315
00316 const char* start = cur;
00317 while (cur != end && *cur != '%') ++cur;
00318
00319
00320 if (cur != start && pending == start) {
00321 result.append(pending, static_cast<std::size_t>(cur - pending));
00322 pending = start = cur;
00323 }
00324
00325
00326 const char* percent = cur;
00327 while (cur != end && *cur == '%') ++cur;
00328
00329
00330
00331 if (cur != start && pending == start) {
00332 std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
00333 result.append(pending, escaped);
00334 pending += escaped * 2;
00335
00336 if (pending != cur && cur == end) {
00337 result.push_back(*pending++);
00338 }
00339 }
00340
00341
00342 if (cur == end || (cur - percent) % 2 == 0) continue;
00343
00344
00345 if (strchr("YmdeHMSzZs%", *cur)) {
00346 if (cur - 1 != pending) {
00347 FormatTM(&result, std::string(pending, cur - 1), tm);
00348 }
00349 switch (*cur) {
00350 case 'Y':
00351
00352
00353 bp = Format64(ep, 0, al.cs.year());
00354 result.append(bp, static_cast<std::size_t>(ep - bp));
00355 break;
00356 case 'm':
00357 bp = Format02d(ep, al.cs.month());
00358 result.append(bp, static_cast<std::size_t>(ep - bp));
00359 break;
00360 case 'd':
00361 case 'e':
00362 bp = Format02d(ep, al.cs.day());
00363 if (*cur == 'e' && *bp == '0') *bp = ' ';
00364 result.append(bp, static_cast<std::size_t>(ep - bp));
00365 break;
00366 case 'H':
00367 bp = Format02d(ep, al.cs.hour());
00368 result.append(bp, static_cast<std::size_t>(ep - bp));
00369 break;
00370 case 'M':
00371 bp = Format02d(ep, al.cs.minute());
00372 result.append(bp, static_cast<std::size_t>(ep - bp));
00373 break;
00374 case 'S':
00375 bp = Format02d(ep, al.cs.second());
00376 result.append(bp, static_cast<std::size_t>(ep - bp));
00377 break;
00378 case 'z':
00379 bp = FormatOffset(ep, al.offset, "");
00380 result.append(bp, static_cast<std::size_t>(ep - bp));
00381 break;
00382 case 'Z':
00383 result.append(al.abbr);
00384 break;
00385 case 's':
00386 bp = Format64(ep, 0, ToUnixSeconds(tp));
00387 result.append(bp, static_cast<std::size_t>(ep - bp));
00388 break;
00389 case '%':
00390 result.push_back('%');
00391 break;
00392 }
00393 pending = ++cur;
00394 continue;
00395 }
00396
00397
00398 if (*cur == ':' && cur + 1 != end) {
00399 if (*(cur + 1) == 'z') {
00400
00401 if (cur - 1 != pending) {
00402 FormatTM(&result, std::string(pending, cur - 1), tm);
00403 }
00404 bp = FormatOffset(ep, al.offset, ":");
00405 result.append(bp, static_cast<std::size_t>(ep - bp));
00406 pending = cur += 2;
00407 continue;
00408 }
00409 if (*(cur + 1) == ':' && cur + 2 != end) {
00410 if (*(cur + 2) == 'z') {
00411
00412 if (cur - 1 != pending) {
00413 FormatTM(&result, std::string(pending, cur - 1), tm);
00414 }
00415 bp = FormatOffset(ep, al.offset, ":*");
00416 result.append(bp, static_cast<std::size_t>(ep - bp));
00417 pending = cur += 3;
00418 continue;
00419 }
00420 if (*(cur + 2) == ':' && cur + 3 != end) {
00421 if (*(cur + 3) == 'z') {
00422
00423 if (cur - 1 != pending) {
00424 FormatTM(&result, std::string(pending, cur - 1), tm);
00425 }
00426 bp = FormatOffset(ep, al.offset, ":*:");
00427 result.append(bp, static_cast<std::size_t>(ep - bp));
00428 pending = cur += 4;
00429 continue;
00430 }
00431 }
00432 }
00433 }
00434
00435
00436 if (*cur != 'E' || ++cur == end) continue;
00437
00438
00439 if (*cur == 'z') {
00440
00441 if (cur - 2 != pending) {
00442 FormatTM(&result, std::string(pending, cur - 2), tm);
00443 }
00444 bp = FormatOffset(ep, al.offset, ":");
00445 result.append(bp, static_cast<std::size_t>(ep - bp));
00446 pending = ++cur;
00447 } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
00448
00449 if (cur - 2 != pending) {
00450 FormatTM(&result, std::string(pending, cur - 2), tm);
00451 }
00452 bp = FormatOffset(ep, al.offset, ":*");
00453 result.append(bp, static_cast<std::size_t>(ep - bp));
00454 pending = cur += 2;
00455 } else if (*cur == '*' && cur + 1 != end &&
00456 (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
00457
00458 if (cur - 2 != pending) {
00459 FormatTM(&result, std::string(pending, cur - 2), tm);
00460 }
00461 char* cp = ep;
00462 bp = Format64(cp, 15, fs.count());
00463 while (cp != bp && cp[-1] == '0') --cp;
00464 switch (*(cur + 1)) {
00465 case 'S':
00466 if (cp != bp) *--bp = '.';
00467 bp = Format02d(bp, al.cs.second());
00468 break;
00469 case 'f':
00470 if (cp == bp) *--bp = '0';
00471 break;
00472 }
00473 result.append(bp, static_cast<std::size_t>(cp - bp));
00474 pending = cur += 2;
00475 } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
00476
00477 if (cur - 2 != pending) {
00478 FormatTM(&result, std::string(pending, cur - 2), tm);
00479 }
00480 bp = Format64(ep, 4, al.cs.year());
00481 result.append(bp, static_cast<std::size_t>(ep - bp));
00482 pending = cur += 2;
00483 } else if (std::isdigit(*cur)) {
00484
00485 int n = 0;
00486 if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
00487 if (*np == 'S' || *np == 'f') {
00488
00489 if (cur - 2 != pending) {
00490 FormatTM(&result, std::string(pending, cur - 2), tm);
00491 }
00492 bp = ep;
00493 if (n > 0) {
00494 if (n > kDigits10_64) n = kDigits10_64;
00495 bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
00496 : fs.count() / kExp10[15 - n]);
00497 if (*np == 'S') *--bp = '.';
00498 }
00499 if (*np == 'S') bp = Format02d(bp, al.cs.second());
00500 result.append(bp, static_cast<std::size_t>(ep - bp));
00501 pending = cur = ++np;
00502 }
00503 }
00504 }
00505 }
00506
00507
00508 if (end != pending) {
00509 FormatTM(&result, std::string(pending, end), tm);
00510 }
00511
00512 return result;
00513 }
00514
00515 namespace {
00516
00517 const char* ParseOffset(const char* dp, const char* mode, int* offset) {
00518 if (dp != nullptr) {
00519 const char first = *dp++;
00520 if (first == '+' || first == '-') {
00521 char sep = mode[0];
00522 int hours = 0;
00523 int minutes = 0;
00524 int seconds = 0;
00525 const char* ap = ParseInt(dp, 2, 0, 23, &hours);
00526 if (ap != nullptr && ap - dp == 2) {
00527 dp = ap;
00528 if (sep != '\0' && *ap == sep) ++ap;
00529 const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
00530 if (bp != nullptr && bp - ap == 2) {
00531 dp = bp;
00532 if (sep != '\0' && *bp == sep) ++bp;
00533 const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
00534 if (cp != nullptr && cp - bp == 2) dp = cp;
00535 }
00536 *offset = ((hours * 60 + minutes) * 60) + seconds;
00537 if (first == '-') *offset = -*offset;
00538 } else {
00539 dp = nullptr;
00540 }
00541 } else if (first == 'Z') {
00542 *offset = 0;
00543 } else {
00544 dp = nullptr;
00545 }
00546 }
00547 return dp;
00548 }
00549
00550 const char* ParseZone(const char* dp, std::string* zone) {
00551 zone->clear();
00552 if (dp != nullptr) {
00553 while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
00554 if (zone->empty()) dp = nullptr;
00555 }
00556 return dp;
00557 }
00558
00559 const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
00560 if (dp != nullptr) {
00561 std::int_fast64_t v = 0;
00562 std::int_fast64_t exp = 0;
00563 const char* const bp = dp;
00564 while (const char* cp = strchr(kDigits, *dp)) {
00565 int d = static_cast<int>(cp - kDigits);
00566 if (d >= 10) break;
00567 if (exp < 15) {
00568 exp += 1;
00569 v *= 10;
00570 v += d;
00571 }
00572 ++dp;
00573 }
00574 if (dp != bp) {
00575 v *= kExp10[15 - exp];
00576 *subseconds = detail::femtoseconds(v);
00577 } else {
00578 dp = nullptr;
00579 }
00580 }
00581 return dp;
00582 }
00583
00584
00585 const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
00586 if (dp != nullptr) {
00587 dp = strptime(dp, fmt, tm);
00588 }
00589 return dp;
00590 }
00591
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 bool parse(const std::string& format, const std::string& input,
00609 const time_zone& tz, time_point<seconds>* sec,
00610 detail::femtoseconds* fs, std::string* err) {
00611
00612 const char* data = input.c_str();
00613
00614
00615 while (std::isspace(*data)) ++data;
00616
00617 const year_t kyearmax = std::numeric_limits<year_t>::max();
00618 const year_t kyearmin = std::numeric_limits<year_t>::min();
00619
00620
00621 bool saw_year = false;
00622 year_t year = 1970;
00623 std::tm tm{};
00624 tm.tm_year = 1970 - 1900;
00625 tm.tm_mon = 1 - 1;
00626 tm.tm_mday = 1;
00627 tm.tm_hour = 0;
00628 tm.tm_min = 0;
00629 tm.tm_sec = 0;
00630 tm.tm_wday = 4;
00631 tm.tm_yday = 0;
00632 tm.tm_isdst = 0;
00633 auto subseconds = detail::femtoseconds::zero();
00634 bool saw_offset = false;
00635 int offset = 0;
00636 std::string zone = "UTC";
00637
00638 const char* fmt = format.c_str();
00639 bool twelve_hour = false;
00640 bool afternoon = false;
00641
00642 bool saw_percent_s = false;
00643 std::int_fast64_t percent_s = 0;
00644
00645
00646 while (data != nullptr && *fmt != '\0') {
00647 if (std::isspace(*fmt)) {
00648 while (std::isspace(*data)) ++data;
00649 while (std::isspace(*++fmt)) continue;
00650 continue;
00651 }
00652
00653 if (*fmt != '%') {
00654 if (*data == *fmt) {
00655 ++data;
00656 ++fmt;
00657 } else {
00658 data = nullptr;
00659 }
00660 continue;
00661 }
00662
00663 const char* percent = fmt;
00664 if (*++fmt == '\0') {
00665 data = nullptr;
00666 continue;
00667 }
00668 switch (*fmt++) {
00669 case 'Y':
00670
00671
00672
00673 data = ParseInt(data, 0, kyearmin, kyearmax, &year);
00674 if (data != nullptr) saw_year = true;
00675 continue;
00676 case 'm':
00677 data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
00678 if (data != nullptr) tm.tm_mon -= 1;
00679 continue;
00680 case 'd':
00681 case 'e':
00682 data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
00683 continue;
00684 case 'H':
00685 data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
00686 twelve_hour = false;
00687 continue;
00688 case 'M':
00689 data = ParseInt(data, 2, 0, 59, &tm.tm_min);
00690 continue;
00691 case 'S':
00692 data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
00693 continue;
00694 case 'I':
00695 case 'l':
00696 case 'r':
00697 twelve_hour = true;
00698 break;
00699 case 'R':
00700 case 'T':
00701 case 'c':
00702 case 'X':
00703 twelve_hour = false;
00704 break;
00705 case 'z':
00706 data = ParseOffset(data, "", &offset);
00707 if (data != nullptr) saw_offset = true;
00708 continue;
00709 case 'Z':
00710 data = ParseZone(data, &zone);
00711 continue;
00712 case 's':
00713 data = ParseInt(data, 0,
00714 std::numeric_limits<std::int_fast64_t>::min(),
00715 std::numeric_limits<std::int_fast64_t>::max(),
00716 &percent_s);
00717 if (data != nullptr) saw_percent_s = true;
00718 continue;
00719 case ':':
00720 if (fmt[0] == 'z' ||
00721 (fmt[0] == ':' &&
00722 (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
00723 data = ParseOffset(data, ":", &offset);
00724 if (data != nullptr) saw_offset = true;
00725 fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
00726 continue;
00727 }
00728 break;
00729 case '%':
00730 data = (*data == '%' ? data + 1 : nullptr);
00731 continue;
00732 case 'E':
00733 if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
00734 data = ParseOffset(data, ":", &offset);
00735 if (data != nullptr) saw_offset = true;
00736 fmt += (fmt[0] == 'z') ? 1 : 2;
00737 continue;
00738 }
00739 if (fmt[0] == '*' && fmt[1] == 'S') {
00740 data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
00741 if (data != nullptr && *data == '.') {
00742 data = ParseSubSeconds(data + 1, &subseconds);
00743 }
00744 fmt += 2;
00745 continue;
00746 }
00747 if (fmt[0] == '*' && fmt[1] == 'f') {
00748 if (data != nullptr && std::isdigit(*data)) {
00749 data = ParseSubSeconds(data, &subseconds);
00750 }
00751 fmt += 2;
00752 continue;
00753 }
00754 if (fmt[0] == '4' && fmt[1] == 'Y') {
00755 const char* bp = data;
00756 data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
00757 if (data != nullptr) {
00758 if (data - bp == 4) {
00759 saw_year = true;
00760 } else {
00761 data = nullptr;
00762 }
00763 }
00764 fmt += 2;
00765 continue;
00766 }
00767 if (std::isdigit(*fmt)) {
00768 int n = 0;
00769 if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
00770 if (*np == 'S') {
00771 data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
00772 if (data != nullptr && *data == '.') {
00773 data = ParseSubSeconds(data + 1, &subseconds);
00774 }
00775 fmt = ++np;
00776 continue;
00777 }
00778 if (*np == 'f') {
00779 if (data != nullptr && std::isdigit(*data)) {
00780 data = ParseSubSeconds(data, &subseconds);
00781 }
00782 fmt = ++np;
00783 continue;
00784 }
00785 }
00786 }
00787 if (*fmt == 'c') twelve_hour = false;
00788 if (*fmt == 'X') twelve_hour = false;
00789 if (*fmt != '\0') ++fmt;
00790 break;
00791 case 'O':
00792 if (*fmt == 'H') twelve_hour = false;
00793 if (*fmt == 'I') twelve_hour = true;
00794 if (*fmt != '\0') ++fmt;
00795 break;
00796 }
00797
00798
00799 const char* orig_data = data;
00800 std::string spec(percent, static_cast<std::size_t>(fmt - percent));
00801 data = ParseTM(data, spec.c_str(), &tm);
00802
00803
00804
00805
00806
00807 if (spec == "%p" && data != nullptr) {
00808 std::string test_input = "1";
00809 test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
00810 const char* test_data = test_input.c_str();
00811 std::tm tmp{};
00812 ParseTM(test_data, "%I%p", &tmp);
00813 afternoon = (tmp.tm_hour == 13);
00814 }
00815 }
00816
00817
00818 if (twelve_hour && afternoon && tm.tm_hour < 12) {
00819 tm.tm_hour += 12;
00820 }
00821
00822 if (data == nullptr) {
00823 if (err != nullptr) *err = "Failed to parse input";
00824 return false;
00825 }
00826
00827
00828 while (std::isspace(*data)) ++data;
00829
00830
00831 if (*data != '\0') {
00832 if (err != nullptr) *err = "Illegal trailing data in input string";
00833 return false;
00834 }
00835
00836
00837 if (saw_percent_s) {
00838 *sec = FromUnixSeconds(percent_s);
00839 *fs = detail::femtoseconds::zero();
00840 return true;
00841 }
00842
00843
00844
00845
00846 time_zone ptz = saw_offset ? utc_time_zone() : tz;
00847
00848
00849 if (tm.tm_sec == 60) {
00850 tm.tm_sec -= 1;
00851 offset -= 1;
00852 subseconds = detail::femtoseconds::zero();
00853 }
00854
00855 if (!saw_year) {
00856 year = year_t{tm.tm_year};
00857 if (year > kyearmax - 1900) {
00858
00859 if (err != nullptr) *err = "Out-of-range year";
00860 return false;
00861 }
00862 year += 1900;
00863 }
00864
00865 const int month = tm.tm_mon + 1;
00866 civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
00867
00868
00869
00870
00871 if (cs.month() != month || cs.day() != tm.tm_mday) {
00872 if (err != nullptr) *err = "Out-of-range field";
00873 return false;
00874 }
00875
00876
00877 if ((offset < 0 && cs > civil_second::max() + offset) ||
00878 (offset > 0 && cs < civil_second::min() + offset)) {
00879 if (err != nullptr) *err = "Out-of-range field";
00880 return false;
00881 }
00882 cs -= offset;
00883
00884 const auto tp = ptz.lookup(cs).pre;
00885
00886 if (tp == time_point<seconds>::max()) {
00887 const auto al = ptz.lookup(time_point<seconds>::max());
00888 if (cs > al.cs) {
00889 if (err != nullptr) *err = "Out-of-range field";
00890 return false;
00891 }
00892 }
00893 if (tp == time_point<seconds>::min()) {
00894 const auto al = ptz.lookup(time_point<seconds>::min());
00895 if (cs < al.cs) {
00896 if (err != nullptr) *err = "Out-of-range field";
00897 return false;
00898 }
00899 }
00900
00901 *sec = tp;
00902 *fs = subseconds;
00903 return true;
00904 }
00905
00906 }
00907 }
00908 }
00909 }