1 // (C) Copyright Howard Hinnant 2 // (C) Copyright 2010-2011 Vicente J. Botet Escriba 3 // Use, modification and distribution are subject to the Boost Software License, 4 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt). 6 7 //===-------------------------- locale ------------------------------------===// 8 // 9 // The LLVM Compiler Infrastructure 10 // 11 // This file is dual licensed under the MIT and the University of Illinois Open 12 // Source Licenses. See LICENSE.TXT for details. 13 // 14 //===----------------------------------------------------------------------===// 15 16 // This code was adapted by Vicente from Howard Hinnant's experimental work 17 // on chrono i/o to Boost and some functions from libc++/locale to emulate the missing time_get::get() 18 19 #ifndef BOOST_CHRONO_IO_TIME_POINT_IO_HPP 20 #define BOOST_CHRONO_IO_TIME_POINT_IO_HPP 21 22 #include <boost/chrono/io/time_point_put.hpp> 23 #include <boost/chrono/io/time_point_get.hpp> 24 #include <boost/chrono/io/duration_io.hpp> 25 #include <boost/chrono/io/ios_base_state.hpp> 26 #include <boost/chrono/io/utility/manip_base.hpp> 27 #include <boost/chrono/time_point.hpp> 28 #include <boost/chrono/clock_string.hpp> 29 #include <boost/chrono/round.hpp> 30 #include <boost/chrono/detail/scan_keyword.hpp> 31 #include <boost/static_assert.hpp> 32 #include <boost/detail/no_exceptions_support.hpp> 33 #include <cstring> 34 #include <locale> 35 #include <ctime> 36 37 #if ( defined BOOST_WINDOWS && ! defined(__CYGWIN__) ) \ 38 || (defined(sun) || defined(__sun)) \ 39 || (defined __IBMCPP__) \ 40 || defined __ANDROID__ \ 41 || defined __QNXNTO__ \ 42 || (defined(_AIX) && defined __GNUC__) 43 #define BOOST_CHRONO_INTERNAL_TIMEGM 44 #endif 45 46 #if (defined BOOST_WINDOWS && ! defined(__CYGWIN__)) \ 47 || ( (defined(sun) || defined(__sun)) && defined __GNUC__) \ 48 || (defined __IBMCPP__) \ 49 || defined __ANDROID__ \ 50 || (defined(_AIX) && defined __GNUC__) 51 #define BOOST_CHRONO_INTERNAL_GMTIME 52 #endif 53 54 #define BOOST_CHRONO_USES_INTERNAL_TIME_GET 55 56 namespace boost 57 { 58 namespace chrono 59 { 60 typedef double fractional_seconds; 61 namespace detail 62 { 63 64 65 template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> > 66 struct time_get 67 { 68 std::time_get<CharT> const &that_; time_getboost::chrono::detail::time_get69 time_get(std::time_get<CharT> const& that) : that_(that) {} 70 71 typedef std::time_get<CharT> facet; 72 typedef typename facet::iter_type iter_type; 73 typedef typename facet::char_type char_type; 74 typedef std::basic_string<char_type> string_type; 75 76 static int get_up_to_n_digitsboost::chrono::detail::time_get77 get_up_to_n_digits( 78 InputIterator& b, InputIterator e, 79 std::ios_base::iostate& err, 80 const std::ctype<CharT>& ct, 81 int n) 82 { 83 // Precondition: n >= 1 84 if (b == e) 85 { 86 err |= std::ios_base::eofbit | std::ios_base::failbit; 87 return 0; 88 } 89 // get first digit 90 CharT c = *b; 91 if (!ct.is(std::ctype_base::digit, c)) 92 { 93 err |= std::ios_base::failbit; 94 return 0; 95 } 96 int r = ct.narrow(c, 0) - '0'; 97 for (++b, --n; b != e && n > 0; ++b, --n) 98 { 99 // get next digit 100 c = *b; 101 if (!ct.is(std::ctype_base::digit, c)) 102 return r; 103 r = r * 10 + ct.narrow(c, 0) - '0'; 104 } 105 if (b == e) 106 err |= std::ios_base::eofbit; 107 return r; 108 } 109 110 get_dayboost::chrono::detail::time_get111 void get_day( 112 int& d, 113 iter_type& b, iter_type e, 114 std::ios_base::iostate& err, 115 const std::ctype<char_type>& ct) const 116 { 117 int t = get_up_to_n_digits(b, e, err, ct, 2); 118 if (!(err & std::ios_base::failbit) && 1 <= t && t <= 31) 119 d = t; 120 else 121 err |= std::ios_base::failbit; 122 } 123 get_monthboost::chrono::detail::time_get124 void get_month( 125 int& m, 126 iter_type& b, iter_type e, 127 std::ios_base::iostate& err, 128 const std::ctype<char_type>& ct) const 129 { 130 int t = get_up_to_n_digits(b, e, err, ct, 2); 131 if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) 132 m = --t; 133 else 134 err |= std::ios_base::failbit; 135 } 136 137 get_year4boost::chrono::detail::time_get138 void get_year4(int& y, 139 iter_type& b, iter_type e, 140 std::ios_base::iostate& err, 141 const std::ctype<char_type>& ct) const 142 { 143 int t = get_up_to_n_digits(b, e, err, ct, 4); 144 if (!(err & std::ios_base::failbit)) 145 y = t - 1900; 146 } 147 148 void get_hourboost::chrono::detail::time_get149 get_hour(int& h, 150 iter_type& b, iter_type e, 151 std::ios_base::iostate& err, 152 const std::ctype<char_type>& ct) const 153 { 154 int t = get_up_to_n_digits(b, e, err, ct, 2); 155 if (!(err & std::ios_base::failbit) && t <= 23) 156 h = t; 157 else 158 err |= std::ios_base::failbit; 159 } 160 161 void get_minuteboost::chrono::detail::time_get162 get_minute(int& m, 163 iter_type& b, iter_type e, 164 std::ios_base::iostate& err, 165 const std::ctype<char_type>& ct) const 166 { 167 int t = get_up_to_n_digits(b, e, err, ct, 2); 168 if (!(err & std::ios_base::failbit) && t <= 59) 169 m = t; 170 else 171 err |= std::ios_base::failbit; 172 } 173 get_secondboost::chrono::detail::time_get174 void get_second(int& s, 175 iter_type& b, iter_type e, 176 std::ios_base::iostate& err, 177 const std::ctype<char_type>& ct) const 178 { 179 int t = get_up_to_n_digits(b, e, err, ct, 2); 180 if (!(err & std::ios_base::failbit) && t <= 60) 181 s = t; 182 else 183 err |= std::ios_base::failbit; 184 } 185 get_white_spaceboost::chrono::detail::time_get186 void get_white_space(iter_type& b, iter_type e, 187 std::ios_base::iostate& err, 188 const std::ctype<char_type>& ct) const 189 { 190 for (; b != e && ct.is(std::ctype_base::space, *b); ++b) 191 ; 192 if (b == e) 193 err |= std::ios_base::eofbit; 194 } 195 get_12_hourboost::chrono::detail::time_get196 void get_12_hour(int& h, 197 iter_type& b, iter_type e, 198 std::ios_base::iostate& err, 199 const std::ctype<char_type>& ct) const 200 { 201 int t = get_up_to_n_digits(b, e, err, ct, 2); 202 if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) 203 h = t; 204 else 205 err |= std::ios_base::failbit; 206 } 207 get_percentboost::chrono::detail::time_get208 void get_percent(iter_type& b, iter_type e, 209 std::ios_base::iostate& err, 210 const std::ctype<char_type>& ct) const 211 { 212 if (b == e) 213 { 214 err |= std::ios_base::eofbit | std::ios_base::failbit; 215 return; 216 } 217 if (ct.narrow(*b, 0) != '%') 218 err |= std::ios_base::failbit; 219 else if(++b == e) 220 err |= std::ios_base::eofbit; 221 } 222 get_day_year_numboost::chrono::detail::time_get223 void get_day_year_num(int& d, 224 iter_type& b, iter_type e, 225 std::ios_base::iostate& err, 226 const std::ctype<char_type>& ct) const 227 { 228 int t = get_up_to_n_digits(b, e, err, ct, 3); 229 if (!(err & std::ios_base::failbit) && 1 <= t && t <= 366) 230 d = --t; 231 else 232 err |= std::ios_base::failbit; 233 } 234 235 void get_weekdayboost::chrono::detail::time_get236 get_weekday(int& w, 237 iter_type& b, iter_type e, 238 std::ios_base::iostate& err, 239 const std::ctype<char_type>& ct) const 240 { 241 int t = get_up_to_n_digits(b, e, err, ct, 1); 242 if (!(err & std::ios_base::failbit) && t <= 6) 243 w = t; 244 else 245 err |= std::ios_base::failbit; 246 } 247 #if 0 248 249 void 250 get_am_pm(int& h, 251 iter_type& b, iter_type e, 252 std::ios_base::iostate& err, 253 const std::ctype<char_type>& ct) const 254 { 255 const string_type* ap = am_pm(); 256 if (ap[0].size() + ap[1].size() == 0) 257 { 258 err |= ios_base::failbit; 259 return; 260 } 261 ptrdiff_t i = detail::scan_keyword(b, e, ap, ap+2, ct, err, false) - ap; 262 if (i == 0 && h == 12) 263 h = 0; 264 else if (i == 1 && h < 12) 265 h += 12; 266 } 267 268 #endif 269 getboost::chrono::detail::time_get270 InputIterator get( 271 iter_type b, iter_type e, 272 std::ios_base& iob, 273 std::ios_base::iostate& err, 274 std::tm* tm, 275 char fmt, char) const 276 { 277 err = std::ios_base::goodbit; 278 const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(iob.getloc()); 279 280 switch (fmt) 281 { 282 case 'a': 283 case 'A': 284 { 285 std::tm tm2; 286 std::memset(&tm2, 0, sizeof(std::tm)); 287 that_.get_weekday(b, e, iob, err, &tm2); 288 //tm->tm_wday = tm2.tm_wday; 289 } 290 break; 291 case 'b': 292 case 'B': 293 case 'h': 294 { 295 std::tm tm2; 296 std::memset(&tm2, 0, sizeof(std::tm)); 297 that_.get_monthname(b, e, iob, err, &tm2); 298 //tm->tm_mon = tm2.tm_mon; 299 } 300 break; 301 // case 'c': 302 // { 303 // const string_type& fm = c(); 304 // b = get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); 305 // } 306 // break; 307 case 'd': 308 case 'e': 309 get_day(tm->tm_mday, b, e, err, ct); 310 break; 311 case 'D': 312 { 313 const char_type fm[] = {'%', 'm', '/', '%', 'd', '/', '%', 'y'}; 314 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); 315 } 316 break; 317 case 'F': 318 { 319 const char_type fm[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd'}; 320 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); 321 } 322 break; 323 case 'H': 324 get_hour(tm->tm_hour, b, e, err, ct); 325 break; 326 case 'I': 327 get_12_hour(tm->tm_hour, b, e, err, ct); 328 break; 329 case 'j': 330 get_day_year_num(tm->tm_yday, b, e, err, ct); 331 break; 332 case 'm': 333 get_month(tm->tm_mon, b, e, err, ct); 334 break; 335 case 'M': 336 get_minute(tm->tm_min, b, e, err, ct); 337 break; 338 case 'n': 339 case 't': 340 get_white_space(b, e, err, ct); 341 break; 342 // case 'p': 343 // get_am_pm(tm->tm_hour, b, e, err, ct); 344 // break; 345 case 'r': 346 { 347 const char_type fm[] = {'%', 'I', ':', '%', 'M', ':', '%', 'S', ' ', '%', 'p'}; 348 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); 349 } 350 break; 351 case 'R': 352 { 353 const char_type fm[] = {'%', 'H', ':', '%', 'M'}; 354 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); 355 } 356 break; 357 case 'S': 358 get_second(tm->tm_sec, b, e, err, ct); 359 break; 360 case 'T': 361 { 362 const char_type fm[] = {'%', 'H', ':', '%', 'M', ':', '%', 'S'}; 363 b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); 364 } 365 break; 366 case 'w': 367 { 368 get_weekday(tm->tm_wday, b, e, err, ct); 369 } 370 break; 371 case 'x': 372 return that_.get_date(b, e, iob, err, tm); 373 // case 'X': 374 // return that_.get_time(b, e, iob, err, tm); 375 // { 376 // const string_type& fm = X(); 377 // b = that_.get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); 378 // } 379 // break; 380 // case 'y': 381 // get_year(tm->tm_year, b, e, err, ct); 382 break; 383 case 'Y': 384 get_year4(tm->tm_year, b, e, err, ct); 385 break; 386 case '%': 387 get_percent(b, e, err, ct); 388 break; 389 default: 390 err |= std::ios_base::failbit; 391 } 392 return b; 393 } 394 395 getboost::chrono::detail::time_get396 InputIterator get( 397 iter_type b, iter_type e, 398 std::ios_base& iob, 399 std::ios_base::iostate& err, std::tm* tm, 400 const char_type* fmtb, const char_type* fmte) const 401 { 402 const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(iob.getloc()); 403 err = std::ios_base::goodbit; 404 while (fmtb != fmte && err == std::ios_base::goodbit) 405 { 406 if (b == e) 407 { 408 err = std::ios_base::failbit; 409 break; 410 } 411 if (ct.narrow(*fmtb, 0) == '%') 412 { 413 if (++fmtb == fmte) 414 { 415 err = std::ios_base::failbit; 416 break; 417 } 418 char cmd = ct.narrow(*fmtb, 0); 419 char opt = '\0'; 420 if (cmd == 'E' || cmd == '0') 421 { 422 if (++fmtb == fmte) 423 { 424 err = std::ios_base::failbit; 425 break; 426 } 427 opt = cmd; 428 cmd = ct.narrow(*fmtb, 0); 429 } 430 b = get(b, e, iob, err, tm, cmd, opt); 431 ++fmtb; 432 } 433 else if (ct.is(std::ctype_base::space, *fmtb)) 434 { 435 for (++fmtb; fmtb != fmte && ct.is(std::ctype_base::space, *fmtb); ++fmtb) 436 ; 437 for ( ; b != e && ct.is(std::ctype_base::space, *b); ++b) 438 ; 439 } 440 else if (ct.toupper(*b) == ct.toupper(*fmtb)) 441 { 442 ++b; 443 ++fmtb; 444 } 445 else 446 err = std::ios_base::failbit; 447 } 448 if (b == e) 449 err |= std::ios_base::eofbit; 450 return b; 451 } 452 453 }; 454 455 456 template <class CharT> 457 class time_manip: public manip<time_manip<CharT> > 458 { 459 std::basic_string<CharT> fmt_; 460 timezone tz_; 461 public: 462 time_manip(timezone tz,std::basic_string<CharT> fmt)463 time_manip(timezone tz, std::basic_string<CharT> fmt) 464 // todo move semantics 465 : 466 fmt_(fmt), tz_(tz) 467 { 468 } 469 470 /** 471 * Change the timezone and time format ios state; 472 */ operator ()(std::ios_base & ios) const473 void operator()(std::ios_base &ios) const 474 { 475 set_time_fmt<CharT> (ios, fmt_); 476 set_timezone(ios, tz_); 477 } 478 }; 479 480 class time_man: public manip<time_man> 481 { 482 timezone tz_; 483 public: 484 time_man(timezone tz)485 time_man(timezone tz) 486 // todo move semantics 487 : 488 tz_(tz) 489 { 490 } 491 492 /** 493 * Change the timezone and time format ios state; 494 */ operator ()(std::ios_base & ios) const495 void operator()(std::ios_base &ios) const 496 { 497 //set_time_fmt<typename out_stream::char_type>(ios, ""); 498 set_timezone(ios, tz_); 499 } 500 }; 501 502 } 503 504 template <class CharT> time_fmt(timezone tz,const CharT * fmt)505 inline detail::time_manip<CharT> time_fmt(timezone tz, const CharT* fmt) 506 { 507 return detail::time_manip<CharT>(tz, fmt); 508 } 509 510 template <class CharT> time_fmt(timezone tz,std::basic_string<CharT> fmt)511 inline detail::time_manip<CharT> time_fmt(timezone tz, std::basic_string<CharT> fmt) 512 { 513 // todo move semantics 514 return detail::time_manip<CharT>(tz, fmt); 515 } 516 time_fmt(timezone f)517 inline detail::time_man time_fmt(timezone f) 518 { 519 return detail::time_man(f); 520 } 521 522 /** 523 * time_fmt_io_saver i/o saver. 524 * 525 * See Boost.IO i/o state savers for a motivating compression. 526 */ 527 template <typename CharT = char, typename Traits = std::char_traits<CharT> > 528 struct time_fmt_io_saver 529 { 530 531 //! the type of the state to restore 532 //typedef std::basic_ostream<CharT, Traits> state_type; 533 typedef std::ios_base state_type; 534 535 //! the type of aspect to save 536 typedef std::basic_string<CharT, Traits> aspect_type; 537 538 /** 539 * Explicit construction from an i/o stream. 540 * 541 * Store a reference to the i/o stream and the value of the associated @c time format . 542 */ time_fmt_io_saverboost::chrono::time_fmt_io_saver543 explicit time_fmt_io_saver(state_type &s) : 544 s_save_(s), a_save_(get_time_fmt<CharT>(s_save_)) 545 { 546 } 547 548 /** 549 * Construction from an i/o stream and a @c time format to restore. 550 * 551 * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. 552 */ time_fmt_io_saverboost::chrono::time_fmt_io_saver553 time_fmt_io_saver(state_type &s, aspect_type new_value) : 554 s_save_(s), a_save_(get_time_fmt<CharT>(s_save_)) 555 { 556 set_time_fmt(s_save_, new_value); 557 } 558 559 /** 560 * Destructor. 561 * 562 * Restores the i/o stream with the format to be restored. 563 */ ~time_fmt_io_saverboost::chrono::time_fmt_io_saver564 ~time_fmt_io_saver() 565 { 566 this->restore(); 567 } 568 569 /** 570 * Restores the i/o stream with the time format to be restored. 571 */ restoreboost::chrono::time_fmt_io_saver572 void restore() 573 { 574 set_time_fmt(s_save_, a_save_); 575 } 576 private: 577 state_type& s_save_; 578 aspect_type a_save_; 579 }; 580 581 /** 582 * timezone_io_saver i/o saver. 583 * 584 * See Boost.IO i/o state savers for a motivating compression. 585 */ 586 struct timezone_io_saver 587 { 588 589 //! the type of the state to restore 590 typedef std::ios_base state_type; 591 //! the type of aspect to save 592 typedef timezone aspect_type; 593 594 /** 595 * Explicit construction from an i/o stream. 596 * 597 * Store a reference to the i/o stream and the value of the associated @c timezone. 598 */ timezone_io_saverboost::chrono::timezone_io_saver599 explicit timezone_io_saver(state_type &s) : 600 s_save_(s), a_save_(get_timezone(s_save_)) 601 { 602 } 603 604 /** 605 * Construction from an i/o stream and a @c timezone to restore. 606 * 607 * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. 608 */ timezone_io_saverboost::chrono::timezone_io_saver609 timezone_io_saver(state_type &s, aspect_type new_value) : 610 s_save_(s), a_save_(get_timezone(s_save_)) 611 { 612 set_timezone(s_save_, new_value); 613 } 614 615 /** 616 * Destructor. 617 * 618 * Restores the i/o stream with the format to be restored. 619 */ ~timezone_io_saverboost::chrono::timezone_io_saver620 ~timezone_io_saver() 621 { 622 this->restore(); 623 } 624 625 /** 626 * Restores the i/o stream with the timezone to be restored. 627 */ restoreboost::chrono::timezone_io_saver628 void restore() 629 { 630 set_timezone(s_save_, a_save_); 631 } 632 private: 633 timezone_io_saver& operator=(timezone_io_saver const& rhs) ; 634 635 state_type& s_save_; 636 aspect_type a_save_; 637 }; 638 639 /** 640 * 641 * @param os 642 * @param tp 643 * @Effects Behaves as a formatted output function. After constructing a @c sentry object, if the @ sentry 644 * converts to true, calls to @c facet.put(os,os,os.fill(),tp) where @c facet is the @c time_point_put<CharT> 645 * facet associated to @c os or a new created instance of the default @c time_point_put<CharT> facet. 646 * @return @c os. 647 */ 648 template <class CharT, class Traits, class Clock, class Duration> 649 std::basic_ostream<CharT, Traits>& operator <<(std::basic_ostream<CharT,Traits> & os,const time_point<Clock,Duration> & tp)650 operator<<(std::basic_ostream<CharT, Traits>& os, const time_point<Clock, Duration>& tp) 651 { 652 653 bool failed = false; 654 BOOST_TRY 655 { 656 std::ios_base::iostate err = std::ios_base::goodbit; 657 BOOST_TRY 658 { 659 typename std::basic_ostream<CharT, Traits>::sentry opfx(os); 660 if (bool(opfx)) 661 { 662 if (!std::has_facet<time_point_put<CharT> >(os.getloc())) 663 { 664 if (time_point_put<CharT> ().put(os, os, os.fill(), tp) .failed()) 665 { 666 err = std::ios_base::badbit; 667 } 668 } 669 else 670 { 671 if (std::use_facet<time_point_put<CharT> >(os.getloc()) .put(os, os, os.fill(), tp).failed()) 672 { 673 err = std::ios_base::badbit; 674 } 675 } 676 os.width(0); 677 } 678 } 679 BOOST_CATCH (...) 680 { 681 bool flag = false; 682 BOOST_TRY 683 { 684 os.setstate(std::ios_base::failbit); 685 } 686 BOOST_CATCH (std::ios_base::failure ) 687 { 688 flag = true; 689 } 690 BOOST_CATCH_END 691 if (flag) throw; 692 } 693 BOOST_CATCH_END 694 if (err) os.setstate(err); 695 return os; 696 } 697 BOOST_CATCH (...) 698 { 699 failed = true; 700 } 701 BOOST_CATCH_END 702 if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); 703 return os; 704 } 705 706 template <class CharT, class Traits, class Clock, class Duration> 707 std::basic_istream<CharT, Traits>& operator >>(std::basic_istream<CharT,Traits> & is,time_point<Clock,Duration> & tp)708 operator>>(std::basic_istream<CharT, Traits>& is, time_point<Clock, Duration>& tp) 709 { 710 std::ios_base::iostate err = std::ios_base::goodbit; 711 712 BOOST_TRY 713 { 714 typename std::basic_istream<CharT, Traits>::sentry ipfx(is); 715 if (bool(ipfx)) 716 { 717 if (!std::has_facet<time_point_get<CharT> >(is.getloc())) 718 { 719 time_point_get<CharT> ().get(is, std::istreambuf_iterator<CharT, Traits>(), is, err, tp); 720 } 721 else 722 { 723 std::use_facet<time_point_get<CharT> >(is.getloc()).get(is, std::istreambuf_iterator<CharT, Traits>(), is, 724 err, tp); 725 } 726 } 727 } 728 BOOST_CATCH (...) 729 { 730 bool flag = false; 731 BOOST_TRY 732 { 733 is.setstate(std::ios_base::failbit); 734 } 735 BOOST_CATCH (std::ios_base::failure ) 736 { 737 flag = true; 738 } 739 BOOST_CATCH_END 740 if (flag) throw; 741 } 742 BOOST_CATCH_END 743 if (err) is.setstate(err); 744 return is; 745 } 746 747 748 namespace detail 749 { 750 751 //#if defined BOOST_CHRONO_INTERNAL_TIMEGM 752 is_leap(int32_t year)753 inline int32_t is_leap(int32_t year) 754 { 755 if(year % 400 == 0) 756 return 1; 757 if(year % 100 == 0) 758 return 0; 759 if(year % 4 == 0) 760 return 1; 761 return 0; 762 } days_from_0(int32_t year)763 inline int32_t days_from_0(int32_t year) 764 { 765 year--; 766 return 365 * year + (year / 400) - (year/100) + (year / 4); 767 } days_from_1970(int32_t year)768 inline int32_t days_from_1970(int32_t year) 769 { 770 static const int32_t days_from_0_to_1970 = days_from_0(1970); 771 return days_from_0(year) - days_from_0_to_1970; 772 } days_from_1jan(int32_t year,int32_t month,int32_t day)773 inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day) 774 { 775 static const int32_t days[2][12] = 776 { 777 { 0,31,59,90,120,151,181,212,243,273,304,334}, 778 { 0,31,60,91,121,152,182,213,244,274,305,335} 779 }; 780 781 return days[is_leap(year)][month-1] + day - 1; 782 } 783 internal_timegm(std::tm const * t)784 inline time_t internal_timegm(std::tm const *t) 785 { 786 int year = t->tm_year + 1900; 787 int month = t->tm_mon; 788 if(month > 11) 789 { 790 year += month/12; 791 month %= 12; 792 } 793 else if(month < 0) 794 { 795 int years_diff = (-month + 11)/12; 796 year -= years_diff; 797 month+=12 * years_diff; 798 } 799 month++; 800 int day = t->tm_mday; 801 int day_of_year = days_from_1jan(year,month,day); 802 int days_since_epoch = days_from_1970(year) + day_of_year ; 803 804 time_t seconds_in_day = 3600 * 24; 805 time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; 806 807 return result; 808 } 809 //#endif 810 811 /** 812 * from_ymd could be made more efficient by using a table 813 * day_count_table indexed by the y%400. 814 * This table could contain the day_count 815 * by*365 + by/4 - by/100 + by/400 816 * 817 * from_ymd = (by/400)*days_by_400_years+day_count_table[by%400] + 818 * days_in_year_before[is_leap_table[by%400]][m-1] + d; 819 */ days_before_years(int32_t y)820 inline unsigned days_before_years(int32_t y) 821 { 822 return y * 365 + y / 4 - y / 100 + y / 400; 823 } 824 825 // Returns year/month/day triple in civil calendar 826 // Preconditions: z is number of days since 1970-01-01 and is in the range: 827 // [numeric_limits<Int>::min(), numeric_limits<Int>::max()-719468]. 828 template <class Int> 829 //constexpr 830 void civil_from_days(Int z,Int & y,unsigned & m,unsigned & d)831 inline civil_from_days(Int z, Int& y, unsigned& m, unsigned& d) BOOST_NOEXCEPT 832 { 833 BOOST_STATIC_ASSERT_MSG(std::numeric_limits<unsigned>::digits >= 18, 834 "This algorithm has not been ported to a 16 bit unsigned integer"); 835 BOOST_STATIC_ASSERT_MSG(std::numeric_limits<Int>::digits >= 20, 836 "This algorithm has not been ported to a 16 bit signed integer"); 837 z += 719468; 838 const Int era = (z >= 0 ? z : z - 146096) / 146097; 839 const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096] 840 const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] 841 y = static_cast<Int>(yoe) + era * 400; 842 const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] 843 const unsigned mp = (5*doy + 2)/153; // [0, 11] 844 d = doy - (153*mp+2)/5 + 1; // [1, 31] 845 m = mp + (mp < 10 ? 3 : -9); // [1, 12] 846 y += (m <= 2); 847 --m; 848 } internal_gmtime(std::time_t const * t,std::tm * tm)849 inline std::tm * internal_gmtime(std::time_t const* t, std::tm *tm) 850 { 851 if (t==0) return 0; 852 if (tm==0) return 0; 853 854 #if 0 855 static const unsigned char 856 day_of_year_month[2][366] = 857 { 858 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, 859 860 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 861 862 } }; 863 864 static const int32_t days_in_year_before[2][13] = 865 { 866 { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, 867 { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 } 868 }; 869 #endif 870 871 const time_t seconds_in_day = 3600 * 24; 872 int32_t days_since_epoch = static_cast<int32_t>(*t / seconds_in_day); 873 int32_t hms = static_cast<int32_t>(*t - seconds_in_day*days_since_epoch); 874 if (hms < 0) { 875 days_since_epoch-=1; 876 hms = seconds_in_day+hms; 877 } 878 879 #if 0 880 int32_t x = days_since_epoch; 881 int32_t y = static_cast<int32_t> (static_cast<long long> (x + 2) * 400 882 / 146097); 883 const int32_t ym1 = y - 1; 884 int32_t doy = x - days_before_years(y); 885 const int32_t doy1 = x - days_before_years(ym1); 886 const int32_t N = std::numeric_limits<int>::digits - 1; 887 const int32_t mask1 = doy >> N; // arithmetic rshift - not portable - but nearly universal 888 const int32_t mask0 = ~mask1; 889 doy = (doy & mask0) | (doy1 & mask1); 890 y = (y & mask0) | (ym1 & mask1); 891 //y -= 32767 + 2; 892 y += 70; 893 tm->tm_year=y; 894 const int32_t leap = is_leap(y); 895 tm->tm_mon = day_of_year_month[leap][doy]-1; 896 tm->tm_mday = doy - days_in_year_before[leap][tm->tm_mon] ; 897 #else 898 int32_t y; 899 unsigned m, d; 900 civil_from_days(days_since_epoch, y, m, d); 901 tm->tm_year=y-1900; tm->tm_mon=m; tm->tm_mday=d; 902 #endif 903 904 tm->tm_hour = hms / 3600; 905 const int ms = hms % 3600; 906 tm->tm_min = ms / 60; 907 tm->tm_sec = ms % 60; 908 909 tm->tm_isdst = -1; 910 (void)mktime(tm); 911 return tm; 912 } 913 914 } // detail 915 #ifndef BOOST_CHRONO_NO_UTC_TIMEPOINT 916 917 #if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT 918 919 template <class CharT, class Traits, class Duration> 920 std::basic_ostream<CharT, Traits>& operator <<(std::basic_ostream<CharT,Traits> & os,const time_point<system_clock,Duration> & tp)921 operator<<(std::basic_ostream<CharT, Traits>& os, const time_point<system_clock, Duration>& tp) 922 { 923 typename std::basic_ostream<CharT, Traits>::sentry ok(os); 924 if (bool(ok)) 925 { 926 bool failed = false; 927 BOOST_TRY 928 { 929 const CharT* pb = 0; //nullptr; 930 const CharT* pe = pb; 931 std::basic_string<CharT> fmt = get_time_fmt<CharT> (os); 932 pb = fmt.data(); 933 pe = pb + fmt.size(); 934 935 timezone tz = get_timezone(os); 936 std::locale loc = os.getloc(); 937 time_t t = system_clock::to_time_t(time_point_cast<system_clock::duration>(tp)); 938 std::tm tm; 939 std::memset(&tm, 0, sizeof(std::tm)); 940 if (tz == timezone::local) 941 { 942 #if defined BOOST_WINDOWS && ! defined(__CYGWIN__) 943 #if BOOST_MSVC < 1400 // localtime_s doesn't exist in vc7.1 944 std::tm *tmp = 0; 945 if ((tmp=localtime(&t)) == 0) 946 failed = true; 947 else 948 tm =*tmp; 949 # else 950 if (localtime_s(&tm, &t) != 0) failed = true; 951 # endif 952 #else 953 if (localtime_r(&t, &tm) == 0) failed = true; 954 #endif 955 } 956 else 957 { 958 #if defined BOOST_CHRONO_INTERNAL_GMTIME 959 if (detail::internal_gmtime(&t, &tm) == 0) failed = true; 960 961 #elif defined BOOST_WINDOWS && ! defined(__CYGWIN__) 962 std::tm *tmp = 0; 963 if((tmp = gmtime(&t)) == 0) 964 failed = true; 965 else 966 tm = *tmp; 967 #else 968 if (gmtime_r(&t, &tm) == 0) failed = true; 969 tm.tm_isdst = -1; 970 (void)mktime(&tm); 971 972 #endif 973 974 } 975 if (!failed) 976 { 977 const std::time_put<CharT>& tpf = std::use_facet<std::time_put<CharT> >(loc); 978 if (pb == pe) 979 { 980 CharT pattern[] = 981 { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; 982 pb = pattern; 983 pe = pb + sizeof (pattern) / sizeof(CharT); 984 failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); 985 if (!failed) 986 { 987 duration<fractional_seconds> d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec); 988 if (d.count() < 10) os << CharT('0'); 989 //if (! os.good()) { 990 // throw "exception"; 991 //} 992 std::ios::fmtflags flgs = os.flags(); 993 os.setf(std::ios::fixed, std::ios::floatfield); 994 //if (! os.good()) { 995 //throw "exception"; 996 //} 997 os.precision(9); 998 os << d.count(); 999 //if (! os.good()) { 1000 //throw "exception"; 1001 //} 1002 os.flags(flgs); 1003 if (tz == timezone::local) 1004 { 1005 CharT sub_pattern[] = 1006 { ' ', '%', 'z' }; 1007 pb = sub_pattern; 1008 pe = pb + +sizeof (sub_pattern) / sizeof(CharT); 1009 failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); 1010 } 1011 else 1012 { 1013 CharT sub_pattern[] = 1014 { ' ', '+', '0', '0', '0', '0', 0 }; 1015 os << sub_pattern; 1016 } 1017 } 1018 } 1019 else 1020 { 1021 failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); 1022 } 1023 } 1024 } 1025 BOOST_CATCH (...) 1026 { 1027 failed = true; 1028 } 1029 BOOST_CATCH_END 1030 if (failed) 1031 { 1032 os.setstate(std::ios_base::failbit | std::ios_base::badbit); 1033 } 1034 } 1035 return os; 1036 } 1037 #endif 1038 1039 namespace detail 1040 { 1041 1042 template <class CharT, class InputIterator> extract_z(InputIterator & b,InputIterator e,std::ios_base::iostate & err,const std::ctype<CharT> & ct)1043 minutes extract_z(InputIterator& b, InputIterator e, std::ios_base::iostate& err, const std::ctype<CharT>& ct) 1044 { 1045 int min = 0; 1046 if (b != e) 1047 { 1048 char cn = ct.narrow(*b, 0); 1049 if (cn != '+' && cn != '-') 1050 { 1051 err |= std::ios_base::failbit; 1052 return minutes(0); 1053 } 1054 int sn = cn == '-' ? -1 : 1; 1055 int hr = 0; 1056 for (int i = 0; i < 2; ++i) 1057 { 1058 if (++b == e) 1059 { 1060 err |= std::ios_base::eofbit | std::ios_base::failbit; 1061 return minutes(0); 1062 } 1063 cn = ct.narrow(*b, 0); 1064 if (! ('0' <= cn && cn <= '9')) 1065 { 1066 err |= std::ios_base::failbit; 1067 return minutes(0); 1068 } 1069 hr = hr * 10 + cn - '0'; 1070 } 1071 for (int i = 0; i < 2; ++i) 1072 { 1073 if (++b == e) 1074 { 1075 err |= std::ios_base::eofbit | std::ios_base::failbit; 1076 return minutes(0); 1077 } 1078 cn = ct.narrow(*b, 0); 1079 if (! ('0' <= cn && cn <= '9')) 1080 { 1081 err |= std::ios_base::failbit; 1082 return minutes(0); 1083 } 1084 min = min * 10 + cn - '0'; 1085 } 1086 if (++b == e) { 1087 err |= std::ios_base::eofbit; 1088 } 1089 min += hr * 60; 1090 min *= sn; 1091 } 1092 else 1093 { 1094 err |= std::ios_base::eofbit | std::ios_base::failbit; 1095 } 1096 return minutes(min); 1097 } 1098 1099 } // detail 1100 1101 #if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT 1102 1103 template <class CharT, class Traits, class Duration> 1104 std::basic_istream<CharT, Traits>& operator >>(std::basic_istream<CharT,Traits> & is,time_point<system_clock,Duration> & tp)1105 operator>>(std::basic_istream<CharT, Traits>& is, time_point<system_clock, Duration>& tp) 1106 { 1107 typename std::basic_istream<CharT, Traits>::sentry ok(is); 1108 if (bool(ok)) 1109 { 1110 std::ios_base::iostate err = std::ios_base::goodbit; 1111 BOOST_TRY 1112 { 1113 const CharT* pb = 0; //nullptr; 1114 const CharT* pe = pb; 1115 std::basic_string<CharT> fmt = get_time_fmt<CharT> (is); 1116 pb = fmt.data(); 1117 pe = pb + fmt.size(); 1118 1119 timezone tz = get_timezone(is); 1120 std::locale loc = is.getloc(); 1121 const std::time_get<CharT>& tg = std::use_facet<std::time_get<CharT> >(loc); 1122 const std::ctype<CharT>& ct = std::use_facet<std::ctype<CharT> >(loc); 1123 tm tm; // {0} 1124 std::memset(&tm, 0, sizeof(std::tm)); 1125 1126 typedef std::istreambuf_iterator<CharT, Traits> It; 1127 if (pb == pe) 1128 { 1129 CharT pattern[] = 1130 { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; 1131 pb = pattern; 1132 pe = pb + sizeof (pattern) / sizeof(CharT); 1133 1134 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET 1135 const detail::time_get<CharT>& dtg(tg); 1136 dtg.get(is, 0, is, err, &tm, pb, pe); 1137 #else 1138 tg.get(is, 0, is, err, &tm, pb, pe); 1139 #endif 1140 if (err & std::ios_base::failbit) goto exit; 1141 fractional_seconds sec; 1142 CharT c = CharT(); 1143 std::ios::fmtflags flgs = is.flags(); 1144 is.setf(std::ios::fixed, std::ios::floatfield); 1145 is.precision(9); 1146 is >> sec; 1147 is.flags(flgs); 1148 if (is.fail()) 1149 { 1150 err |= std::ios_base::failbit; 1151 goto exit; 1152 } 1153 It i(is); 1154 It eof; 1155 c = *i; 1156 if (++i == eof || c != ' ') 1157 { 1158 err |= std::ios_base::failbit; 1159 goto exit; 1160 } 1161 minutes min = detail::extract_z(i, eof, err, ct); 1162 1163 if (err & std::ios_base::failbit) goto exit; 1164 time_t t; 1165 1166 #if defined BOOST_CHRONO_INTERNAL_TIMEGM 1167 t = detail::internal_timegm(&tm); 1168 #else 1169 t = timegm(&tm); 1170 #endif 1171 tp = time_point_cast<Duration>( 1172 system_clock::from_time_t(t) - min + round<system_clock::duration> (duration<fractional_seconds> (sec)) 1173 ); 1174 } 1175 else 1176 { 1177 const CharT z[2] = 1178 { '%', 'z' }; 1179 const CharT* fz = std::search(pb, pe, z, z + 2); 1180 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET 1181 const detail::time_get<CharT>& dtg(tg); 1182 dtg.get(is, 0, is, err, &tm, pb, fz); 1183 #else 1184 tg.get(is, 0, is, err, &tm, pb, fz); 1185 #endif 1186 minutes minu(0); 1187 if (fz != pe) 1188 { 1189 if (err != std::ios_base::goodbit) 1190 { 1191 err |= std::ios_base::failbit; 1192 goto exit; 1193 } 1194 It i(is); 1195 It eof; 1196 minu = detail::extract_z(i, eof, err, ct); 1197 if (err & std::ios_base::failbit) goto exit; 1198 if (fz + 2 != pe) 1199 { 1200 if (err != std::ios_base::goodbit) 1201 { 1202 err |= std::ios_base::failbit; 1203 goto exit; 1204 } 1205 #if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET 1206 const detail::time_get<CharT>& dtg(tg); 1207 dtg.get(is, 0, is, err, &tm, fz + 2, pe); 1208 #else 1209 tg.get(is, 0, is, err, &tm, fz + 2, pe); 1210 #endif 1211 if (err & std::ios_base::failbit) goto exit; 1212 } 1213 } 1214 tm.tm_isdst = -1; 1215 time_t t; 1216 if (tz == timezone::utc || fz != pe) 1217 { 1218 #if defined BOOST_CHRONO_INTERNAL_TIMEGM 1219 t = detail::internal_timegm(&tm); 1220 #else 1221 t = timegm(&tm); 1222 #endif 1223 } 1224 else 1225 { 1226 t = mktime(&tm); 1227 } 1228 tp = time_point_cast<Duration>( 1229 system_clock::from_time_t(t) - minu 1230 ); 1231 } 1232 } 1233 BOOST_CATCH (...) 1234 { 1235 err |= std::ios_base::badbit | std::ios_base::failbit; 1236 } 1237 BOOST_CATCH_END 1238 exit: is.setstate(err); 1239 } 1240 return is; 1241 } 1242 1243 #endif 1244 #endif //UTC 1245 } // chrono 1246 1247 } 1248 1249 #endif // header 1250