
Hi, I have been fixing some bugs on Boost.Chrono #9274 <https://svn.boost.org/trac/boost/ticket/9274> lost of precission on system_clock input <https://svn.boost.org/trac/boost/ticket/9274> #9276 <https://svn.boost.org/trac/boost/ticket/9276> output from a system_clock::time_point get a time_point that is one day later than expected <https://svn.boost.org/trac/boost/ticket/9276> #9265 <https://svn.boost.org/trac/boost/ticket/9265> time_point_output_h test crashes regression test <https://svn.boost.org/trac/boost/ticket/9265> #8328 <https://svn.boost.org/trac/boost/ticket/8328> chrono crashes visual studio 2012 regression tests <https://svn.boost.org/trac/boost/ticket/8328> The concerned change sets are 19:00 Changeset /[86410]/ by viboes <https://svn.boost.org/trac/boost/changeset/86410> Thread: Try to fix system_clock::time_point output on windows. 18:01 Changeset /[86384]/ by viboes <https://svn.boost.org/trac/boost/changeset/86384> Chrono: try to avoid the crash with msvc 11 on chrono_io. 17:36 Changeset /[86383]/ by viboes <https://svn.boost.org/trac/boost/changeset/86383> Chrono: set precission to 9 so that there is no lost with the hisgest ... 14:27 Changeset /[86376]/ by viboes <https://svn.boost.org/trac/boost/changeset/86376> Chrono: fix two important issues with Boost.Chrono IO v2 on windows * ... 14:54 Changeset /[86357]/ by viboes <https://svn.boost.org/trac/boost/changeset/86357> Chrono: don't run test_good_utc_fmt_system_clock on windows as this is ... I would like to merge these changeset to release. Is it time to do it before releasing boost 1.55? Best, Vicente Patch: svn diff boost/chrono/detail/inlined/win/chrono.hpp boost/chrono/io/time_point_io.hpp libs/chrono/test/io/time_point_output.cpp libs/chrono/example/io_ex1.cpp Index: boost/chrono/detail/inlined/win/chrono.hpp =================================================================== --- boost/chrono/detail/inlined/win/chrono.hpp (revision 86326) +++ boost/chrono/detail/inlined/win/chrono.hpp (working copy) @@ -109,8 +109,11 @@ { ec.clear(); } - return time_point(duration( - (static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime)); + return system_clock::time_point( + system_clock::duration( + ((static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime) + -116444736000000000LL + )); } #endif Index: boost/chrono/io/time_point_io.hpp =================================================================== --- boost/chrono/io/time_point_io.hpp (revision 86326) +++ boost/chrono/io/time_point_io.hpp (working copy) @@ -28,6 +28,7 @@ #include <boost/chrono/clock_string.hpp> #include <boost/chrono/round.hpp> #include <boost/chrono/detail/scan_keyword.hpp> +#include <boost/static_assert.hpp> #include <boost/detail/no_exceptions_support.hpp> #include <cstring> #include <locale> @@ -46,9 +47,11 @@ { namespace chrono { + typedef double fractional_seconds; namespace detail { + template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> > struct time_get { @@ -758,6 +761,7 @@ { 0,31,59,90,120,151,181,212,243,273,304,334}, { 0,31,60,91,121,152,182,213,244,274,305,335} }; + return days[is_leap(year)][month-1] + day - 1; } @@ -779,7 +783,7 @@ month++; int day = t->tm_mday; int day_of_year = days_from_1jan(year,month,day); - int days_since_epoch = days_from_1970(year) + day_of_year; + int days_since_epoch = days_from_1970(year) + day_of_year ; time_t seconds_in_day = 3600 * 24; time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; @@ -801,11 +805,36 @@ return y * 365 + y / 4 - y / 100 + y / 400; } + // Returns year/month/day triple in civil calendar + // Preconditions: z is number of days since 1970-01-01 and is in the range: + // [numeric_limits<Int>::min(), numeric_limits<Int>::max()-719468]. + template <class Int> + //constexpr + void + inline civil_from_days(Int z, Int& y, unsigned& m, unsigned& d) BOOST_NOEXCEPT + { + BOOST_STATIC_ASSERT_MSG(std::numeric_limits<unsigned>::digits >= 18, + "This algorithm has not been ported to a 16 bit unsigned integer"); + BOOST_STATIC_ASSERT_MSG(std::numeric_limits<Int>::digits >= 20, + "This algorithm has not been ported to a 16 bit signed integer"); + z += 719468; + const Int era = (z >= 0 ? z : z - 146096) / 146097; + const unsigned doe = static_cast<unsigned>(z - era * 146097); // [0, 146096] + const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] + y = static_cast<Int>(yoe) + era * 400; + const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] + const unsigned mp = (5*doy + 2)/153; // [0, 11] + d = doy - (153*mp+2)/5 + 1; // [1, 31] + m = mp + (mp < 10 ? 3 : -9); // [1, 12] + y += (m <= 2); + --m; + } inline std::tm * internal_gmtime(std::time_t const* t, std::tm *tm) { if (t==0) return 0; if (tm==0) return 0; +#if 0 static const unsigned char day_of_year_month[2][366] = { @@ -820,6 +849,7 @@ { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 } }; +#endif const time_t seconds_in_day = 3600 * 24; int32_t days_since_epoch = static_cast<int32_t>(*t / seconds_in_day); @@ -829,6 +859,7 @@ hms = seconds_in_day+hms; } +#if 0 int32_t x = days_since_epoch; int32_t y = static_cast<int32_t> (static_cast<long long> (x + 2) * 400 / 146097); @@ -843,16 +874,23 @@ //y -= 32767 + 2; y += 70; tm->tm_year=y; - const bool leap = is_leap(y); + const int32_t leap = is_leap(y); tm->tm_mon = day_of_year_month[leap][doy]-1; - tm->tm_mday = doy - days_in_year_before[leap][day_of_year_month[leap][doy] - 1]; + tm->tm_mday = doy - days_in_year_before[leap][tm->tm_mon] ; +#else + int32_t y; + unsigned m, d; + civil_from_days(days_since_epoch, y, m, d); + tm->tm_year=y-1900; tm->tm_mon=m; tm->tm_mday=d; +#endif - tm->tm_hour = hms / 3600; const int ms = hms % 3600; tm->tm_min = ms / 60; tm->tm_sec = ms % 60; + tm->tm_isdst = -1; + (void)mktime(tm); return tm; } @@ -907,6 +945,9 @@ tm = *tmp; #else if (gmtime_r(&t, &tm) == 0) failed = true; + tm.tm_isdst = -1; + (void)mktime(&tm); + #endif } @@ -922,7 +963,7 @@ failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); if (!failed) { - duration<double> d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec); + duration<fractional_seconds> d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec); if (d.count() < 10) os << CharT('0'); //if (! os.good()) { // throw "exception"; @@ -932,6 +973,7 @@ //if (! os.good()) { //throw "exception"; //} + os.precision(9); os << d.count(); //if (! os.good()) { //throw "exception"; @@ -1058,12 +1100,8 @@ const std::time_get<CharT>& tg = std::use_facet<std::time_get<CharT> >(loc); const std::ctype<CharT>& ct = std::use_facet<std::ctype<CharT> >(loc); tm tm; // {0} - tm.tm_year=0; - tm.tm_mon=0; - tm.tm_mday=0; - tm.tm_hour=0; - tm.tm_min=0; - tm.tm_sec=0; + std::memset(&tm, 0, sizeof(std::tm)); + typedef std::istreambuf_iterator<CharT, Traits> It; if (pb == pe) { @@ -1079,9 +1117,13 @@ tg.get(is, 0, is, err, &tm, pb, pe); #endif if (err & std::ios_base::failbit) goto exit; - double sec; + fractional_seconds sec; CharT c = CharT(); + std::ios::fmtflags flgs = is.flags(); + is.setf(std::ios::fixed, std::ios::floatfield); + is.precision(9); is >> sec; + is.flags(flgs); if (is.fail()) { err |= std::ios_base::failbit; @@ -1099,13 +1141,14 @@ if (err & std::ios_base::failbit) goto exit; time_t t; + #if BOOST_CHRONO_INTERNAL_TIMEGM t = detail::internal_timegm(&tm); #else t = timegm(&tm); #endif tp = time_point_cast<Duration>( - system_clock::from_time_t(t) - min + round<microseconds> (duration<double> (sec)) + system_clock::from_time_t(t) - min + round<system_clock::duration> (duration<fractional_seconds> (sec)) ); } else Index: libs/chrono/test/io/time_point_output.cpp =================================================================== --- libs/chrono/test/io/time_point_output.cpp (revision 86326) +++ libs/chrono/test/io/time_point_output.cpp (working copy) @@ -148,68 +148,102 @@ using namespace boost::chrono; using namespace boost; - test_good_system_clock("1970-01-01 02:00:00.000000 +0000", hours(2), duration_style::prefix); - test_good_system_clock("1970-01-01 02:00:00.000000 +0000", hours(2), duration_style::symbol); + test_good_system_clock("1970-01-01 02:00:00.000000000 +0000", hours(2), duration_style::prefix); + test_good_system_clock("1970-01-01 02:00:00.000000000 +0000", hours(2), duration_style::symbol); - test_good_prefix_system_clock("1970-01-01 02:00:00.000000 +0000", hours(2)); - test_good_prefix_system_clock("1970-01-01 00:02:00.000000 +0000", minutes(2)); - test_good_prefix_system_clock("1970-01-01 00:00:02.000000 +0000", seconds(2)); - test_good_prefix_system_clock("1970-01-01 00:00:01.000000 +0000", seconds(1)); - test_good_prefix_system_clock("1969-12-31 23:59:59.000000 +0000", seconds(-1)); - test_good_prefix_system_clock("1970-01-01 00:00:00.000000 +0000", seconds(0)); - test_good_prefix_system_clock("1970-01-01 00:00:00.002000 +0000", milliseconds(2)); - test_good_prefix_system_clock("1970-01-01 00:00:00.000002 +0000", microseconds(2)); - test_good_prefix_system_clock("1970-01-01 00:00:00.000000 +0000", nanoseconds(2)); - test_good_prefix_system_clock("1970-01-01 00:00:00.200000 +0000", duration<boost::int_least64_t, deci> (2)); - test_good_prefix_system_clock("1970-01-01 00:00:00.066667 +0000", duration<boost::int_least64_t, ratio<1, 30> > (2)); + test_good_prefix_system_clock("1970-01-01 02:00:00.000000000 +0000", hours(2)); + test_good_prefix_system_clock("1970-01-01 00:02:00.000000000 +0000", minutes(2)); + test_good_prefix_system_clock("1970-01-01 00:00:02.000000000 +0000", seconds(2)); + test_good_prefix_system_clock("1970-01-01 00:00:01.000000000 +0000", seconds(1)); + test_good_prefix_system_clock("1969-12-31 23:59:59.000000000 +0000", seconds(-1)); + test_good_prefix_system_clock("1970-01-01 00:00:00.000000000 +0000", seconds(0)); + test_good_prefix_system_clock("1970-01-01 00:00:00.002000000 +0000", milliseconds(2)); + test_good_prefix_system_clock("1970-01-01 00:00:00.000002000 +0000", microseconds(2)); + test_good_prefix_system_clock("1970-01-01 00:00:00.000000002 +0000", nanoseconds(2)); + test_good_prefix_system_clock("1970-01-01 00:00:00.200000000 +0000", duration<boost::int_least64_t, deci> (2)); + test_good_prefix_system_clock("1970-01-01 00:00:00.066666667 +0000", duration<boost::int_least64_t, ratio<1, 30> > (2)); - test_good_symbol_system_clock("1970-01-01 02:00:00.000000 +0000", hours(2)); - test_good_symbol_system_clock("1970-01-01 00:02:00.000000 +0000", minutes(2)); - test_good_symbol_system_clock("1970-01-01 00:00:02.000000 +0000", seconds(2)); - test_good_symbol_system_clock("1970-01-01 00:00:00.002000 +0000", milliseconds(2)); - test_good_symbol_system_clock("1970-01-01 00:00:00.000000 +0000", nanoseconds(2)); - test_good_symbol_system_clock("1970-01-01 00:00:00.200000 +0000", duration<boost::int_least64_t, deci> (2)); - test_good_symbol_system_clock("1970-01-01 00:00:00.066667 +0000", duration<boost::int_least64_t, ratio<1, 30> > (2)); + test_good_symbol_system_clock("1970-01-01 02:00:00.000000000 +0000", hours(2)); + test_good_symbol_system_clock("1970-01-01 00:02:00.000000000 +0000", minutes(2)); + test_good_symbol_system_clock("1970-01-01 00:00:02.000000000 +0000", seconds(2)); + test_good_symbol_system_clock("1970-01-01 00:00:00.002000000 +0000", milliseconds(2)); + test_good_symbol_system_clock("1970-01-01 00:00:00.000000002 +0000", nanoseconds(2)); + test_good_symbol_system_clock("1970-01-01 00:00:00.200000000 +0000", duration<boost::int_least64_t, deci> (2)); + test_good_symbol_system_clock("1970-01-01 00:00:00.066666667 +0000", duration<boost::int_least64_t, ratio<1, 30> > (2)); test_good_utc_fmt_system_clock("1970-01-01 02:00:00", "%Y-%m-%d %H:%M:%S", hours(2)); test_good_utc_fmt_system_clock("1970-01-01 02", "%Y-%m-%d %H", hours(2)); - +#if ! defined(BOOST_CHRONO_WINDOWS_API) test_good_utc_fmt_system_clock ("1970-01-01 02:00:00", "%Y-%m-%d %T", hours(2)); test_good_utc_fmt_system_clock ("1970-01-01 02:00", "%Y-%m-%d %R", hours(2)); test_good_utc_fmt_system_clock ("% 1970-01-01 02:00", "%% %Y-%m-%d %R", hours(2)); test_good_utc_fmt_system_clock ("1970-01-01 02:00 Thursday January", "%Y-%m-%d %R %A %B", hours(2)); - +#endif } + +#endif +#if BOOST_CHRONO_VERSION == 2 void test_gmtime(std::time_t t) { std::cout << "t " << t << std::endl; + puts(ctime(&t)); std::tm tm; + std::memset(&tm, 0, sizeof(std::tm)); if (boost::chrono::detail::internal_gmtime(&t, &tm)) { - std::cout << "year " << tm.tm_year << std::endl; - std::cout << "month " << tm.tm_mon << std::endl; - std::cout << "day " << tm.tm_mday << std::endl; - std::cout << "hour " << tm.tm_hour << std::endl; - std::cout << "min " << tm.tm_min << std::endl; - std::cout << "sec " << tm.tm_sec << std::endl; + tm.tm_isdst = -1; + (void)mktime(&tm); + std::tm tm2; + std::memset(&tm2, 0, sizeof(std::tm)); + if (gmtime_r(&t, &tm2)) + { + tm2.tm_isdst = -1; + (void)mktime(&tm2); + + BOOST_TEST_EQ( tm.tm_year , tm2.tm_year ); + BOOST_TEST_EQ( tm.tm_mon , tm2.tm_mon ); + BOOST_TEST_EQ( tm.tm_mday , tm2.tm_mday ); + BOOST_TEST_EQ( tm.tm_hour , tm2.tm_hour); + BOOST_TEST_EQ( tm.tm_min , tm2.tm_min ); + BOOST_TEST_EQ( tm.tm_sec , tm2.tm_sec ); + BOOST_TEST_EQ( tm.tm_wday , tm2.tm_wday ); + BOOST_TEST_EQ( tm.tm_yday , tm2.tm_yday ); + BOOST_TEST_EQ( tm.tm_isdst , tm2.tm_isdst ); + } } + } #endif + int main() { -// test_gmtime( 0 ); -// test_gmtime( -1 ); -// test_gmtime( +1 ); -// test_gmtime( 0 - (3600 * 24) ); -// test_gmtime( -1 - (3600 * 24) ); -// test_gmtime( +1 - (3600 * 24) ); -// test_gmtime( 0 + (3600 * 24) ); -// test_gmtime( -1 + (3600 * 24) ); -// test_gmtime( +1 + (3600 * 24) ); +#if BOOST_CHRONO_VERSION == 2 + test_gmtime( 0 ); + test_gmtime( -1 ); + test_gmtime( +1 ); + test_gmtime( 0 - (3600 * 24) ); + test_gmtime( -1 - (3600 * 24) ); + test_gmtime( +1 - (3600 * 24) ); + test_gmtime( 0 + (3600 * 24) ); + test_gmtime( -1 + (3600 * 24) ); + test_gmtime( +1 + (3600 * 24) ); + test_gmtime( 0 + 365*(3600 * 24) ); + test_gmtime( 0 + 10LL*365*(3600 * 24) ); + test_gmtime( 0 + 15LL*365*(3600 * 24) ); + test_gmtime( 0 + 17LL*365*(3600 * 24) ); + test_gmtime( 0 + 18LL*365*(3600 * 24) ); + test_gmtime( 0 + 19LL*365*(3600 * 24) ); + test_gmtime( 0 + 19LL*365*(3600 * 24)+ (3600 * 24)); + test_gmtime( 0 + 19LL*365*(3600 * 24)+ 3*(3600 * 24)); + test_gmtime( 0 + 19LL*365*(3600 * 24)+ 4*(3600 * 24)); + test_gmtime( 0 + 20LL*365*(3600 * 24) ); + test_gmtime( 0 + 40LL*365*(3600 * 24) ); +#endif + std::cout << "high_resolution_clock=" << std::endl; check_all<boost::chrono::high_resolution_clock> (); #ifdef BOOST_CHRONO_HAS_CLOCK_STEADY @@ -239,6 +273,13 @@ check_all<boost::chrono::process_cpu_clock> (); #endif +#if BOOST_CHRONO_VERSION == 2 + boost::chrono::system_clock::time_point tp = boost::chrono::system_clock::now(); + std::cout << tp << std::endl; + time_t t = boost::chrono::system_clock::to_time_t(tp); + test_gmtime( t ); +#endif + return boost::report_errors(); } Index: libs/chrono/example/io_ex1.cpp =================================================================== --- libs/chrono/example/io_ex1.cpp (revision 86326) +++ libs/chrono/example/io_ex1.cpp (working copy) @@ -53,10 +53,13 @@ << ClockTick(3) + nanoseconds(10) << '\n'; cout << "\nsystem_clock::now() = " << system_clock::now() << '\n'; +#if defined _MSC_VER && _MSC_VER == 1700 +#else #if BOOST_CHRONO_VERSION==2 cout << "\nsystem_clock::now() = " << time_fmt(chrono::timezone::local) << system_clock::now() << '\n'; cout << "\nsystem_clock::now() = " << time_fmt(chrono::timezone::local,"%Y/%m/%d") << system_clock::now() << '\n'; #endif +#endif #ifdef BOOST_CHRONO_HAS_CLOCK_STEADY cout << "steady_clock::now() = " << steady_clock::now() << '\n';