From 1eed461d06b02854d9310d5ab0198eccd2be1d1d Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Wed, 3 Oct 2018 17:51:55 -0400 Subject: [PATCH] Model the TAI-UTC difference between 1961 and 1972 --- include/date/tz.h | 103 +++++++++++++++++++++++++- test/clock_cast_test/local_t.pass.cpp | 2 +- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/include/date/tz.h b/include/date/tz.h index 49e4320..1eba540 100644 --- a/include/date/tz.h +++ b/include/date/tz.h @@ -2057,6 +2057,73 @@ template using tai_seconds = tai_time; +namespace detail +{ + +template +inline +std::chrono::duration +mjd(sys_time tp) +{ + using namespace std::chrono; +// constexpr auto off = sys_days{1970_y/1/1} - (sys_days{-4713_y/11/24} + hours{12}) - +// dday{2400000.5}; + constexpr days off{40587}; + return tp.time_since_epoch() + off; +} + +template +Duration +pre_leap(sys_time tp) +{ + using namespace std::chrono; + using dsec = duration; + if (tp >= sys_days(1972_y/January/1)) + return seconds{10}; + if (tp < sys_days(1961_y/January/1)) + return Duration{0}; + if (tp < sys_days(1961_y/August/1)) + return duration_cast( + dsec{1.422818} + (mjd(tp) - days{37300}).count() * dsec{0.001296}); + if (tp < sys_days(1962_y/January/1)) + return duration_cast( + dsec{1.372818} + (mjd(tp) - days{37300}).count() * dsec{0.001296}); + if (tp < sys_days(1963_y/November/1)) + return duration_cast( + dsec{1.845858} + (mjd(tp) - days{37665}).count() * dsec{0.0011232}); + if (tp < sys_days(1964_y/January/1)) + return duration_cast( + dsec{1.945858} + (mjd(tp) - days{37665}).count() * dsec{0.0011232}); + if (tp < sys_days(1964_y/April/1)) + return duration_cast( + dsec{3.240130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1964_y/September/1)) + return duration_cast( + dsec{3.340130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1965_y/January/1)) + return duration_cast( + dsec{3.440130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1965_y/March/1)) + return duration_cast( + dsec{3.540130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1965_y/July/1)) + return duration_cast( + dsec{3.640130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1965_y/September/1)) + return duration_cast( + dsec{3.740130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1966_y/January/1)) + return duration_cast( + dsec{3.840130} + (mjd(tp) - days{38761}).count() * dsec{0.001296}); + if (tp < sys_days(1968_y/February/1)) + return duration_cast( + dsec{4.313170} + (mjd(tp) - days{39126}).count() * dsec{0.002592}); + return duration_cast( + dsec{4.213170} + (mjd(tp) - days{39126}).count() * dsec{0.002592}); +} + +} // namespace detail + template inline utc_time::type> @@ -2065,7 +2132,8 @@ tai_clock::to_utc(const tai_time& t) NOEXCEPT using namespace std::chrono; using CD = typename std::common_type::type; return utc_time{t.time_since_epoch()} - - (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); + (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + + detail::pre_leap(sys_time(to_local(t).time_since_epoch()))); } template @@ -2076,7 +2144,8 @@ tai_clock::from_utc(const utc_time& t) NOEXCEPT using namespace std::chrono; using CD = typename std::common_type::type; return tai_time{t.time_since_epoch()} + - (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + seconds{10}); + (sys_days(year{1970}/January/1) - sys_days(year{1958}/January/1) + + detail::pre_leap(sys_time(t.time_since_epoch()))); } inline @@ -2178,6 +2247,34 @@ template using gps_seconds = gps_time; +#if 1 + +template +inline +utc_time::type> +gps_clock::to_utc(const gps_time& t) NOEXCEPT +{ + using namespace std::chrono; + using CD = typename std::common_type::type; + return tai_clock::to_utc(tai_time{t.time_since_epoch()} + + (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1958}/January/1) + + seconds{19})); +} + +template +inline +gps_time::type> +gps_clock::from_utc(const utc_time& t) NOEXCEPT +{ + using namespace std::chrono; + using CD = typename std::common_type::type; + return gps_time{tai_clock::from_utc(t).time_since_epoch()} - + (sys_days(year{1980}/January/Sunday[1]) - sys_days(year{1958}/January/1) + + seconds{19}); +} + +#else + template inline utc_time::type> @@ -2202,6 +2299,8 @@ gps_clock::from_utc(const utc_time& t) NOEXCEPT seconds{9}); } +#endif + inline gps_clock::time_point gps_clock::now() diff --git a/test/clock_cast_test/local_t.pass.cpp b/test/clock_cast_test/local_t.pass.cpp index c80459d..a1e5de6 100644 --- a/test/clock_cast_test/local_t.pass.cpp +++ b/test/clock_cast_test/local_t.pass.cpp @@ -82,7 +82,7 @@ main() assert(clock_cast(tt) == lt); assert(tt.time_since_epoch() == seconds(0)); - auto lu = local_days{1958_y/January/1_d} - seconds(10); + auto lu = local_days{1958_y/January/1_d}; auto ut = clock_cast(lu); assert(clock_cast(ut) == tt); }