From 984a974f6a5173cfc17b5e85c46aa17ecc6a8c21 Mon Sep 17 00:00:00 2001 From: xanthos Date: Tue, 17 Oct 2023 14:07:15 +0300 Subject: [PATCH] added tests --- src/dat.cpp | 6 +- src/datetime_tops.hpp | 5 +- src/dtcalendar.hpp | 106 +++++----- src/dtfund.hpp | 50 ++--- src/hms_time.hpp | 2 +- src/tpdate.hpp | 6 +- src/ydoy_date.cpp | 6 +- src/ymd_date.cpp | 1 - test/sofa/cal2jd.cpp | 9 +- test/sofa/dat.cpp | 283 +++++++++++++------------- test/sofa/epj.cpp | 19 +- test/sofa/jd2cal.cpp | 15 +- test/unit_tests/datetime.cpp | 30 +-- test/unit_tests/datetime_addition.cpp | 38 ++-- test/unit_tests/interval.cpp | 34 ++-- test/unit_tests/mjd.cpp | 9 +- test/unit_tests/ydoy_date.cpp | 14 +- test/unit_tests/ymd_date.cpp | 12 +- 18 files changed, 329 insertions(+), 316 deletions(-) diff --git a/src/dat.cpp b/src/dat.cpp index 201f515..15d7706 100644 --- a/src/dat.cpp +++ b/src/dat.cpp @@ -77,16 +77,16 @@ int dso::dat(dso::modified_julian_day mjd, int &extra_sec_in_day) noexcept { [&](const mjd_dat::change &c) { return mjd >= dso::modified_julian_day(c.mjd); }); - + /* extra seconds in day */ extra_sec_in_day = 0; /* check to see if given MJD is a leap-second day (i.e. has more seconds) */ if (it != mjd_dat::changes.rend() && it != mjd_dat::changes.rbegin()) { /* given MJD is on a leap-insertion date (i.e. day prior to next leap) */ - if (mjd == dso::modified_julian_day((it-1)->mjd-1)) { + if (mjd == dso::modified_julian_day((it - 1)->mjd - 1)) { /* DAT at next period */ - int next_leap = (it-1)->delat; + int next_leap = (it - 1)->delat; extra_sec_in_day = next_leap - it->delat; } } diff --git a/src/datetime_tops.hpp b/src/datetime_tops.hpp index 42c1ad7..08c65bc 100644 --- a/src/datetime_tops.hpp +++ b/src/datetime_tops.hpp @@ -5,8 +5,8 @@ #define __DSO_DATETIME_GENERIC_TEMPLATE_OPERATIONS_HPP__ #include "dtconcepts.hpp" -#include #include +#include namespace dso { @@ -56,7 +56,6 @@ constexpr bool operator==(DType a, DType b) noexcept { return a.__member_const_ref__() == b.__member_const_ref__(); } - /** Overload bool operator '!=' for datetime fundamental types. * This function will be resolved for any type DType, which * 1. has a member (variable) DType::is_dt_fundamental_type set to true, and @@ -415,6 +414,6 @@ constexpr Strg cast_to(Ssrc s) noexcept { return Strg(numerator / Ssrc::template sec_factor()); } -}/* namespace dso */ +} /* namespace dso */ #endif diff --git a/src/dtcalendar.hpp b/src/dtcalendar.hpp index d0b52a6..3a43b5b 100644 --- a/src/dtcalendar.hpp +++ b/src/dtcalendar.hpp @@ -7,12 +7,12 @@ #ifndef __DTCALENDAR_NGPT__HPP__ #define __DTCALENDAR_NGPT__HPP__ -#include "dtfund.hpp" #include "dtconcepts.hpp" +#include "dtfund.hpp" #include +#include #include #include -#include namespace dso { @@ -90,34 +90,23 @@ struct RawDatetimeDifference { * A datetime_interval represents a time (datetime) interval or period, i.e. * 5 days, 12 hours and 49 seconds. We assume a continuous time scale, no leap * seconds are taken into consideration --this is only an interval not an - * actual datetime instance--). + * actual datetime instance--. * A datetime_interval instance can only have positive (or zero) values (for - * both its members). + * both of its members). However, seperate field is stored (i.e. \p m_sign) to + * hold 'sign' information, so that a datetime_interval instance can be easily + * used with a datetime instance. That means that e.g. 'adding' a negative + * interval, will extend the datetime in the past. * * A datetime_interval instance has two fundamental parts (members): * - a day part (i.e. holding the days), and * - a time part (i.e. holding any type S i.e. any second type) + * - a sign (i.e. an integer) * * The purpose of this class is to work together with the datetime class. * * @tparam S Any class of 'second type', i.e. any class S that has a (static) * member variable S::is_of_sec_type set to true. This can be * dso::seconds, dso::milliseconds, dso::microseconds. - * - * - * @note - Any instance of the class has two members, m_days an integer - * representing the (MJ) days and m_secs, an instance of type S, - * representing the fractional day part. However, the parts may be - * mixed (!), that is if e.g. S is dso::seconds, the m_secs part may - * actualy have any value, including ones larger than 86400. That is - * to say that an instance can be constructed as: - * \code{.cpp} - * datetime_interval d {modified_julian_day(1), - * seconds(90000)}; - * \endcode - * Should the user want the "normalization" of the instance (that is - * remove whole days from the m_secs part and add them to the m_days - * part), call the function datetime_interval::normalize(). */ #if __cplusplus >= 202002L template @@ -130,15 +119,28 @@ class datetime_interval { public: /** Default constructor (everything set to 0). */ - explicit constexpr datetime_interval() noexcept - : m_days(0), m_secs(0){}; + explicit constexpr datetime_interval() noexcept : m_days(0), m_secs(0){}; - /** Constructor from number of days and number of *seconds. The sign of the - * interval is taken from \p days. The number of days and number of *seconds - * of the interval, are considered positive (i.e. absolute values of input - * parameters). + /** Constructor from number of days and number of *seconds. + * + * The sign of the interval is extracted from \p days. The number of days + * and number of *seconds of the interval, are considered positive (i.e. + * absolute values of input parameters). + * For example to construct an interval of 2days + 2sec, use: + * datetime_interval interval(2, seconds(2)); + * If you want to mark this interval as 'negative' (normally for algebraic + * operations with a datetime isntance), use: + * datetime_interval interval(-2, seconds(2)); + * If you want to mark a 'negative' interval but the number of days is zero, + * then you should use: + * datetime_interval interval(0, seconds(-2)); + * or + * datetime_interval interval(seconds(-2)); + * and **NOT** + * datetime_interval interval(-0, seconds(2)); + * since there is no 'signed 0' value. * - * @warning It is not possible to differentiate between -0 and +1. Hence, + * @warning It is not possible to differentiate between -0 and +0. Hence, * to construct an interval of 0 days and 1 secs (S), use: * datetime_interval(S(-1)) and **NOT** * datetime_interval(-0, S(1)) @@ -149,8 +151,8 @@ class datetime_interval { normalize(); }; - /** Constructor from number of *seconds. The sign of the interval is taken - * from \p secs. The number of *seconds of the interval is considered + /** Constructor from number of *seconds. The sign of the interval is taken + * from \p secs. The number of *seconds of the interval is considered * positive (i.e. absolute values of input parameter). */ constexpr datetime_interval(S secs) noexcept @@ -180,21 +182,23 @@ class datetime_interval { DaysIntType days() const noexcept { return m_days; } /** return number of *secs in interval, always positive */ - S/*ecIntType*/ sec() const noexcept { return S(m_secs); } + S sec() const noexcept { return S(m_secs); } /** return number of *secs in interval, signed (not including whole days) */ - S /*ecIntType*/ signed_sec() const noexcept { - return S(std::copysign(m_secs, m_sign)); - } + S signed_sec() const noexcept { return S(std::copysign(m_secs, m_sign)); } /** return the sign of the interval */ int sign() const noexcept { return m_sign; } - S/*ecIntType*/ unsigned_total_sec() const noexcept { + /** Return the interval (days+*seconds) in seconds type S, ignoring sign */ + S unsigned_total_sec() const noexcept { return S(m_secs + S::max_in_day * m_days); } - S/*ecIntType*/ signed_total_sec() const noexcept { + /** Return the interval (days+*seconds) in seconds type S, using a negative + * value if the instance is marked as 'negative' + */ + S signed_total_sec() const noexcept { return S(std::copysign(unsigned_total_sec().as_underlying_type(), m_sign)); } @@ -213,11 +217,11 @@ class datetime_interval { * - a date part (i.e. holding the year/month/day), and * - a time part (i.e. holding hours/minutes/ *seconds) * - * A datetime holds both a date and a time (i.e. of day). The date is stored + * A datetime holds both a date and a time (i.e. of day). The date is stored * as a Modified Julian Day (i.e. dso::modified_julian_day). The time of day * can be stored via any class of 'second type', i.e. dso::seconds, - * dso::milliseconds, or dso::microseconds). Every method in the class will - * (including constructors) will take provisions such that the *seconds are + * dso::milliseconds, or dso::microseconds). Every method in the class will + * (including constructors) will take provisions such that the *seconds are * in fact *seconds of day (i.e. do not surpass one day). * Never use negative times; they actually have no physical meaning. Besides * that, they can cause UB. @@ -431,7 +435,7 @@ class datetime { */ /** Operator '+' where the right-hand-side is an interval. - * Note that the addition here is algebraic, i.e. the interval is added to + * Note that the addition here is algebraic, i.e. the interval is added to * or subtracted from the instance, depending on its sign. * Hence, an interval of e.g. (- 2 days, 30 sec) will actually be subtracted * from the instance, not added to it. @@ -445,7 +449,7 @@ class datetime { } /** Add a time interval to a datetime instance. - * Note that the addition here is algebraic, i.e. the interval is added to + * Note that the addition here is algebraic, i.e. the interval is added to * or subtracted from the instance, depending on its sign. * Hence, an interval of e.g. (- 2 days, 30 sec) will actually be subtracted * from the instance, not added to it. @@ -462,21 +466,29 @@ class datetime { /* big date at d1, small at d2 */ auto d1 = *this; auto d2 = dt; - int sgn=1; - if (m_mjd < dt.m_mjd) { + int sgn = 1; + if (*this < dt) { d1 = d2; d2 = *this; sgn = -1; } + /* seconds, could be negative */ SecIntType secs = d1.sec().as_underlying_type() - d2.sec().as_underlying_type(); - if (secs < 0) { - d1.m_mjd -= 1; - secs = S::max_in_day + secs; - } + /* so handle negative seconds */ + // if (secs < 0) { + // d1.m_mjd -= 1; + // secs = S::max_in_day + secs; + // } + /* branchless TODO which is faster ? */ + d1.m_mjd = d1.m_mjd - modified_julian_day(1 * (secs < 0)); + secs = secs + S::max_in_day * (secs < 0); DaysIntType days = d1.imjd().as_underlying_type() - d2.imjd().as_underlying_type(); - return datetime_interval(days*sgn, S(secs)); + /* note that id days are 0 and the sign is negative, it must be applied to + * the seconds part */ + return datetime_interval(days * sgn, + S(std::copysign(secs, (days == 0) * sgn))); } /** Cast to any datetime instance, regardless of what T is @@ -682,7 +694,7 @@ class datetime { modified_julian_day m_mjd; /** Modified Julian Day */ S m_sec; /** Time of day in S precision. */ -}; /* datetime */ +}; /* datetime */ /// Difference between two dates in MJdays and T. /// Diff is dt1 - dt2 diff --git a/src/dtfund.hpp b/src/dtfund.hpp index 1e2d08b..caaebfb 100644 --- a/src/dtfund.hpp +++ b/src/dtfund.hpp @@ -137,9 +137,9 @@ inline constexpr double jd2epj(double dj1, double dj2) noexcept { /** @brief Modified Julian Date to Julian Epoch * - * Convert a Modified Julian date to a Julian Epoch. The MJD can be given as a - * single value (i.e. in parameter \p mjd0) or can be split into two parts, - * (e.g. the first being the intergal part of MJD and the second be fractional + * Convert a Modified Julian date to a Julian Epoch. The MJD can be given as a + * single value (i.e. in parameter \p mjd0) or can be split into two parts, + * (e.g. the first being the intergal part of MJD and the second be fractional * day). * * @see jd2epj @@ -148,7 +148,7 @@ inline constexpr double jd2epj(double dj1, double dj2) noexcept { * @param[in] mjd1 Second part of MJD (if any), such that MJD = mjd0 + mjd1 * @return The input date as Julian Epoch. */ -inline constexpr double mjd2epj(double mjd0, double mjd1=0e0) noexcept { +inline constexpr double mjd2epj(double mjd0, double mjd1 = 0e0) noexcept { return 2000e0 + ((mjd0 - J2000_MJD) / DAYS_IN_JULIAN_YEAR + mjd1 / DAYS_IN_JULIAN_YEAR); } @@ -164,7 +164,7 @@ inline constexpr double epj2mjd(double epj) noexcept { return J2000_MJD + (epj - 2000e0) * DAYS_IN_JULIAN_YEAR; } } /* namespace core */ - + /** @brief For a given UTC date, calculate delta(AT) = TAI-UTC. * * The day of month is actually not needed, since all leap second insertions @@ -707,37 +707,37 @@ class ymd_date { constexpr bool is_valid() const noexcept { return __dom.is_valid(__year, __month); } - + /** operator '==' for ymd_date instances */ bool operator==(const ymd_date &d) const noexcept { - return ((__year == d.yr()) && (__dom == d.dm()) && (__month==d.mn())); + return ((__year == d.yr()) && (__dom == d.dm()) && (__month == d.mn())); } - + /** operator '!=' for ymd_date instances */ bool operator!=(const ymd_date &d) const noexcept { return !(this->operator==(d)); } /** @brief Transform to year and day-of-year - * The function will first check that the instance is a valid date, before - * performing the transformation (to year and day of year). This is done - * because an invalid ymd_date can result in a seamingly valid ydoy_date + * The function will first check that the instance is a valid date, before + * performing the transformation (to year and day of year). This is done + * because an invalid ymd_date can result in a seamingly valid ydoy_date * (e.g. constructing a 29/2 date on a non-leap year). */ ydoy_date to_ydoy() const; /** get/set year */ - constexpr year &yr() noexcept {return __year;} + constexpr year &yr() noexcept { return __year; } /** get/set month */ - constexpr month &mn() noexcept {return __month;} + constexpr month &mn() noexcept { return __month; } /** get/set day of month */ - constexpr day_of_month &dm() noexcept {return __dom;} + constexpr day_of_month &dm() noexcept { return __dom; } /** get year */ - constexpr year yr() const noexcept {return __year;} + constexpr year yr() const noexcept { return __year; } /** get month */ - constexpr month mn() const noexcept {return __month;} + constexpr month mn() const noexcept { return __month; } /** get day of month */ - constexpr day_of_month dm() const noexcept {return __dom;} + constexpr day_of_month dm() const noexcept { return __dom; } private: year __year; /** the year */ @@ -762,8 +762,8 @@ class ydoy_date { constexpr ydoy_date(year y = year{}, day_of_year d = day_of_year{}) noexcept : __year(y), __doy(d) {} - /** @brief Constructor from a Year/Month/DayOfMonth instance - * In case the input argument \p ymd is not a valid date, the constructor + /** @brief Constructor from a Year/Month/DayOfMonth instance + * In case the input argument \p ymd is not a valid date, the constructor * will throw. */ ydoy_date(const ymd_date &ymd) @@ -781,20 +781,20 @@ class ydoy_date { bool operator==(const ydoy_date &d) const noexcept { return (__year == d.yr()) && (__doy == d.dy()); } - + /** operator '!=' for ydoy_date instances */ bool operator!=(const ydoy_date &d) const noexcept { return !(this->operator==(d)); } - + /** get/set year */ - year &yr() noexcept {return __year;} + year &yr() noexcept { return __year; } /** get/set day of year */ - day_of_year &dy() noexcept {return __doy;} + day_of_year &dy() noexcept { return __doy; } /** get year */ - constexpr year yr() const noexcept {return __year;} + constexpr year yr() const noexcept { return __year; } /** get day of year */ - constexpr day_of_year dy() const noexcept {return __doy;} + constexpr day_of_year dy() const noexcept { return __doy; } private: year __year; /** the year */ diff --git a/src/hms_time.hpp b/src/hms_time.hpp index ab8d399..090155c 100644 --- a/src/hms_time.hpp +++ b/src/hms_time.hpp @@ -1,5 +1,5 @@ /** @file - * A class to represent hours/minutes/seconds, i.e. a time instance. + * A class to represent hours/minutes/seconds, i.e. a time instance. */ #ifndef __DSO_DATETIME_HMSTIME_HPP__ #define __DSO_DATETIME_HMSTIME_HPP__ diff --git a/src/tpdate.hpp b/src/tpdate.hpp index fa1119f..4251781 100644 --- a/src/tpdate.hpp +++ b/src/tpdate.hpp @@ -22,9 +22,9 @@ struct TwoPartJulianDate { double d0, d1; }; -/** Given an MJD, turn it to a JD and return it split in a convinient way - * The way the (returned) JD is split is determined by the template parameter - * \p S. +/** Given an MJD, turn it to a JD and return it split in a convinient way + * The way the (returned) JD is split is determined by the template parameter + * \p S. */ template TwoPartJulianDate jd_split(double mjd, double fday) noexcept { diff --git a/src/ydoy_date.cpp b/src/ydoy_date.cpp index f17fb87..10252e2 100644 --- a/src/ydoy_date.cpp +++ b/src/ydoy_date.cpp @@ -3,13 +3,13 @@ dso::ymd_date dso::ydoy_date::to_ymd() const noexcept { int guess = static_cast(__doy.as_underlying_type() * 0.032); int leap = yr().is_leap(); - int more = ((dy().as_underlying_type() - - dso::core::month_day[leap][guess + 1]) > 0); + int more = + ((dy().as_underlying_type() - dso::core::month_day[leap][guess + 1]) > 0); /* assign */ ymd_date yd; yd.yr() = yr(); yd.mn() = month(guess + more + 1); yd.dm() = day_of_month(dy().as_underlying_type() - - dso::core::month_day[leap][guess + more]); + dso::core::month_day[leap][guess + more]); return yd; } diff --git a/src/ymd_date.cpp b/src/ymd_date.cpp index 025dc95..a33807f 100644 --- a/src/ymd_date.cpp +++ b/src/ymd_date.cpp @@ -14,7 +14,6 @@ dso::ymd_date::ymd_date(const dso::ydoy_date &ydoy) { __dom = ymd.dm(); } - dso::ydoy_date dso::ymd_date::to_ydoy() const { if (!is_valid()) { throw std::invalid_argument( diff --git a/test/sofa/cal2jd.cpp b/test/sofa/cal2jd.cpp index 96e6b70..055edaa 100644 --- a/test/sofa/cal2jd.cpp +++ b/test/sofa/cal2jd.cpp @@ -14,7 +14,7 @@ int main() { std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ - for (long i=0; i -#include #include #include +#include +#include -using dso::ymd_date; -using dso::year; -using dso::month; using dso::day_of_month; +using dso::month; +using dso::year; +using dso::ymd_date; const std::array leap_insertion_dates = { ymd_date{year(1972), month(6), day_of_month(30)}, @@ -47,154 +47,149 @@ bool is_leap_insertion_day(const ymd_date &ymd) noexcept { return it != leap_insertion_dates.end(); } - /* number of tests to perform (pre template parameter) */ - const long num_tests = 1'000'000; +/* number of tests to perform (pre template parameter) */ +const long num_tests = 1'000'000; - int main() { - /* Generators for random numbers ... */ - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> ydstr(1972, 2050); /* range for years */ - std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ - std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ +int main() { + /* Generators for random numbers ... */ + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> ydstr(1972, 2050); /* range for years */ + std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ + std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ - double jd0, jd1; - for (long i = 0; i < num_tests; i++) { - const int iy = ydstr(gen); - const int im = mdstr(gen); - const int id = ddstr(gen); - double deltat; - ymd_date ymd{dso::year(iy), dso::month(im), dso::day_of_month(id)}; - if (!ymd.is_valid()) { - /* erronuous date, SOFA should verify that! */ - assert(iauCal2jd(iy, im, id, &jd0, &jd1) < 0); - } else { - /* get DAT from SOFA for 0hours in day */ - assert(iauDat(iy, im, id, 0e0, &deltat) >= 0); - /* get DAT from libgdatetime */ - int dat = dso::dat(ymd); - assert(deltat == (double)dat); - } - if (i % 10) - printf("%ld/%ld\r", i, num_tests); + double jd0, jd1; + for (long i = 0; i < num_tests; i++) { + const int iy = ydstr(gen); + const int im = mdstr(gen); + const int id = ddstr(gen); + double deltat; + ymd_date ymd{dso::year(iy), dso::month(im), dso::day_of_month(id)}; + if (!ymd.is_valid()) { + /* erronuous date, SOFA should verify that! */ + assert(iauCal2jd(iy, im, id, &jd0, &jd1) < 0); + } else { + /* get DAT from SOFA for 0hours in day */ + assert(iauDat(iy, im, id, 0e0, &deltat) >= 0); + /* get DAT from libgdatetime */ + int dat = dso::dat(ymd); + assert(deltat == (double)dat); } + if (i % 10) + printf("%ld/%ld\r", i, num_tests); + } - int extra; - int leap_seconds_found=0; - - /* leap second years in range [1972 to now] */ - const std::vector leap = {2016, 2015, 2012, 2008, 2005, 1998, 1997, - 1995, 1994, 1993, 1992, 1990, 1989, 1987, - 1985, 1983, 1982, 1981, 1979, 1978, 1977, - 1976, 1975, 1974, 1973, 1972}; - for (const auto y : leap) { - double deltat; - /* 29/06/YYYY - no insertion of leap second */ - ymd_date ymd{dso::year(y), dso::month(6), dso::day_of_month(29)}; - assert(iauDat(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); - assert(deltat == (double)dso::dat(ymd)); - /* transform to MJD */ - assert(iauCal2jd(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); - assert(jd0 == dso::MJD0_JD); - /* compute DAT using the MJD */ - auto mjd = dso::modified_julian_day((long)jd1); - assert(deltat == (double)dso::dat(mjd)); - dso::dat(mjd, extra); - if (extra) { - //printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), - // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); - ++leap_seconds_found; - assert(is_leap_insertion_day(ymd)); - } + int extra; + int leap_seconds_found = 0; - /* 30/06/YYYY - insertion of leap second could happen ! */ - ymd = ymd_date(dso::year(y), dso::month(6), dso::day_of_month(30)); - assert(iauDat(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); - assert(deltat == (double)dso::dat(ymd)); - assert(iauCal2jd(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); - assert(jd0 == dso::MJD0_JD); - mjd = dso::modified_julian_day((long)jd1); - assert(deltat == (double)dso::dat(mjd)); - dso::dat(mjd, extra); - if (extra) { - //printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), - // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); - ++leap_seconds_found; - assert(is_leap_insertion_day(ymd)); - } + /* leap second years in range [1972 to now] */ + const std::vector leap = {2016, 2015, 2012, 2008, 2005, 1998, 1997, + 1995, 1994, 1993, 1992, 1990, 1989, 1987, + 1985, 1983, 1982, 1981, 1979, 1978, 1977, + 1976, 1975, 1974, 1973, 1972}; + for (const auto y : leap) { + double deltat; + /* 29/06/YYYY - no insertion of leap second */ + ymd_date ymd{dso::year(y), dso::month(6), dso::day_of_month(29)}; + assert(iauDat(ymd.yr().as_underlying_type(), ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); + assert(deltat == (double)dso::dat(ymd)); + /* transform to MJD */ + assert(iauCal2jd(ymd.yr().as_underlying_type(), + ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); + assert(jd0 == dso::MJD0_JD); + /* compute DAT using the MJD */ + auto mjd = dso::modified_julian_day((long)jd1); + assert(deltat == (double)dso::dat(mjd)); + dso::dat(mjd, extra); + if (extra) { + // printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), + // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); + ++leap_seconds_found; + assert(is_leap_insertion_day(ymd)); + } - /* 01/07/YYYY - no insertion of leap second */ - ymd = ymd_date(dso::year(y), dso::month(7), dso::day_of_month(1)); - assert(iauDat(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); - assert(deltat == (double)dso::dat(ymd)); - assert(iauCal2jd(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); - assert(jd0 == dso::MJD0_JD); - mjd = dso::modified_julian_day((long)jd1); - assert(deltat == (double)dso::dat(mjd)); - dso::dat(mjd, extra); - if (extra) { - //printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), - // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); - ++leap_seconds_found; - assert(is_leap_insertion_day(ymd)); - } + /* 30/06/YYYY - insertion of leap second could happen ! */ + ymd = ymd_date(dso::year(y), dso::month(6), dso::day_of_month(30)); + assert(iauDat(ymd.yr().as_underlying_type(), ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); + assert(deltat == (double)dso::dat(ymd)); + assert(iauCal2jd(ymd.yr().as_underlying_type(), + ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); + assert(jd0 == dso::MJD0_JD); + mjd = dso::modified_julian_day((long)jd1); + assert(deltat == (double)dso::dat(mjd)); + dso::dat(mjd, extra); + if (extra) { + // printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), + // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); + ++leap_seconds_found; + assert(is_leap_insertion_day(ymd)); + } - /* 01/01/YYYY - no insertion of leap second */ - ymd = ymd_date(dso::year(y), dso::month(1), dso::day_of_month(1)); - assert(iauDat(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); - assert(deltat == (double)dso::dat(ymd)); - assert(iauCal2jd(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); - assert(jd0 == dso::MJD0_JD); - mjd = dso::modified_julian_day((long)jd1); - assert(deltat == (double)dso::dat(mjd)); - dso::dat(mjd, extra); - if (extra) { - //printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), - // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); - ++leap_seconds_found; - assert(is_leap_insertion_day(ymd)); - } + /* 01/07/YYYY - no insertion of leap second */ + ymd = ymd_date(dso::year(y), dso::month(7), dso::day_of_month(1)); + assert(iauDat(ymd.yr().as_underlying_type(), ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); + assert(deltat == (double)dso::dat(ymd)); + assert(iauCal2jd(ymd.yr().as_underlying_type(), + ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); + assert(jd0 == dso::MJD0_JD); + mjd = dso::modified_julian_day((long)jd1); + assert(deltat == (double)dso::dat(mjd)); + dso::dat(mjd, extra); + if (extra) { + // printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), + // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); + ++leap_seconds_found; + assert(is_leap_insertion_day(ymd)); + } + + /* 01/01/YYYY - no insertion of leap second */ + ymd = ymd_date(dso::year(y), dso::month(1), dso::day_of_month(1)); + assert(iauDat(ymd.yr().as_underlying_type(), ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); + assert(deltat == (double)dso::dat(ymd)); + assert(iauCal2jd(ymd.yr().as_underlying_type(), + ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); + assert(jd0 == dso::MJD0_JD); + mjd = dso::modified_julian_day((long)jd1); + assert(deltat == (double)dso::dat(mjd)); + dso::dat(mjd, extra); + if (extra) { + // printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), + // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); + ++leap_seconds_found; + assert(is_leap_insertion_day(ymd)); + } - /* 31/01/YYYY - insertion of leap second could happen ! */ - ymd = ymd_date(dso::year(y), dso::month(12), dso::day_of_month(31)); - assert(iauDat(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); - assert(deltat == (double)dso::dat(ymd)); - assert(iauCal2jd(ymd.yr().as_underlying_type(), - ymd.mn().as_underlying_type(), - ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); - assert(jd0 == dso::MJD0_JD); - mjd = dso::modified_julian_day((long)jd1); - assert(deltat == (double)dso::dat(mjd)); - dso::dat(mjd, extra); - if (extra) { - //printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), - // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); - ++leap_seconds_found; - assert(is_leap_insertion_day(ymd)); - } + /* 31/01/YYYY - insertion of leap second could happen ! */ + ymd = ymd_date(dso::year(y), dso::month(12), dso::day_of_month(31)); + assert(iauDat(ymd.yr().as_underlying_type(), ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), 0e0, &deltat) >= 0); + assert(deltat == (double)dso::dat(ymd)); + assert(iauCal2jd(ymd.yr().as_underlying_type(), + ymd.mn().as_underlying_type(), + ymd.dm().as_underlying_type(), &jd0, &jd1) == 0); + assert(jd0 == dso::MJD0_JD); + mjd = dso::modified_julian_day((long)jd1); + assert(deltat == (double)dso::dat(mjd)); + dso::dat(mjd, extra); + if (extra) { + // printf("->leap at %d/%02d/%02d\n", ymd.yr().as_underlying_type(), + // ymd.mn().as_underlying_type(), ymd.dm().as_underlying_type()); + ++leap_seconds_found; + assert(is_leap_insertion_day(ymd)); } + } - /* all leap seconds found */ - assert(leap_seconds_found == 27); + /* all leap seconds found */ + assert(leap_seconds_found == 27); - printf("All tests ok!\n"); - return 0; + printf("All tests ok!\n"); + return 0; } diff --git a/test/sofa/epj.cpp b/test/sofa/epj.cpp index 11dbb26..8a90f63 100644 --- a/test/sofa/epj.cpp +++ b/test/sofa/epj.cpp @@ -1,8 +1,8 @@ #include "dtfund.hpp" #include "sofa.h" #include -#include #include +#include /* number of tests to perform (pre template parameter) */ long num_tests = 1'000'000; @@ -15,7 +15,7 @@ int main() { std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ - for (long i=0; i -#include #include +#include using namespace dso; @@ -14,15 +14,15 @@ int main() { std::random_device rd; std::mt19937 gen(rd()); /* range for JD, 1972to 2035 */ - std::uniform_int_distribution<> jddstr(2441317,2464328); + std::uniform_int_distribution<> jddstr(2441317, 2464328); int iy, id, im; double fd; - for (long i=0; i(0,nsec(1)); + dt += datetime_interval(0, nsec(1)); assert(dt > d); dt += datetime_interval(nsec(-1)); assert(dt == d); dt += datetime_interval(nsec(-1)); - assert(dt.imjd() == d.imjd()-modified_julian_day(1)); - for (int j=0; j<86400; j++) { - dt += datetime_interval(0,nsec(1*TOSEC)); + assert(dt.imjd() == d.imjd() - modified_julian_day(1)); + for (int j = 0; j < 86400; j++) { + dt += datetime_interval(0, nsec(1 * TOSEC)); /* reached one nsec before end of day */ } assert(dt.imjd() == d.imjd()); /* add onw more nsec; we are now on next day */ - dt += datetime_interval(0,nsec(1)); - assert(dt.imjd() == d.imjd()+modified_julian_day(1)); + dt += datetime_interval(0, nsec(1)); + assert(dt.imjd() == d.imjd() + modified_julian_day(1)); /* and nsec of day should be 0 */ assert(dt.sec() == nsec(0)); /* add two whole days and 11 nsec */ dt = d; - dt += datetime_interval(0,nsec(11 + 2*86400*TOSEC)); - assert(dt.imjd() == d.imjd()+modified_julian_day(2)); + dt += datetime_interval(0, nsec(11 + 2 * 86400 * TOSEC)); + assert(dt.imjd() == d.imjd() + modified_julian_day(2)); assert(dt.sec() == nsec(11)); /* or do it this way ... */ auto dt2 = d; - dt2 += datetime_interval(2,nsec(11)); - assert( dt == dt2 ); + dt2 += datetime_interval(2, nsec(11)); + assert(dt == dt2); /* remove two whole days and 11 nsec */ dt = d; - dt += datetime_interval(0,nsec(-(11 + 2*86400*TOSEC))); - assert(dt.imjd() == d.imjd()-modified_julian_day(3)); + dt += datetime_interval(0, nsec(-(11 + 2 * 86400 * TOSEC))); + assert(dt.imjd() == d.imjd() - modified_julian_day(3)); assert(dt.sec() == nsec(nsec::max_in_day - 11)); /* or do it this way ... */ dt2 = d; - dt2 += datetime_interval(-2,nsec(11)); - assert( dt == dt2 ); + dt2 += datetime_interval(-2, nsec(11)); + assert(dt == dt2); ++testnr; + if (testnr % 10) + printf("%d/%ld\r", testnr, num_tests); } } diff --git a/test/unit_tests/datetime_addition.cpp b/test/unit_tests/datetime_addition.cpp index 9e34321..33a53ab 100644 --- a/test/unit_tests/datetime_addition.cpp +++ b/test/unit_tests/datetime_addition.cpp @@ -4,7 +4,7 @@ using namespace dso; -constexpr const long num_tests = 1'000; +constexpr const long num_tests = 1'000'000; using nsec = dso::nanoseconds; typedef nsec::underlying_type SecIntType; constexpr const SecIntType TOSEC = nsec::sec_factor(); @@ -15,34 +15,36 @@ int main() { std::mt19937 gen(rd()); std::uniform_int_distribution<> ydstr(1972, 2050); /* range for years */ std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ - std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ - //std::uniform_int_distribution<> hrdstr(0, 23); /* range for day of month */ - //std::uniform_int_distribution<> mndstr(0, 59); /* range for day of month */ + std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ std::uniform_int_distribution nsdstr( 0, nsec::max_in_day); /* range for day of month */ - int testnr = 0,ok; - datetime d1,d2; + int testnr = 0, ok; + datetime d1, d2, d3; while (testnr < num_tests) { /* do we have a valid date ? */ try { - d1 = datetime{year(ydstr(gen)), month(mdstr(gen)), - day_of_month(ddstr(gen)), nsec(nsdstr(gen))}; - d2 = datetime{year(ydstr(gen)), month(mdstr(gen)), - day_of_month(ddstr(gen)), nsec(nsdstr(gen))}; - ok = 1; + d1 = datetime{year(ydstr(gen)), month(mdstr(gen)), + day_of_month(ddstr(gen)), nsec(nsdstr(gen))}; + d2 = datetime{year(ydstr(gen)), month(mdstr(gen)), + day_of_month(ddstr(gen)), nsec(nsdstr(gen))}; + /* d3 on same day as d2 */ + d3 = datetime{d2.imjd(), nsec(nsdstr(gen))}; + ok = 1; } catch (std::exception &) { ok = 0; } if (ok) { - const auto interval = d2 - d1; - //printf("d1=%08ld %015ld\n", d1.imjd().as_underlying_type(), d1.sec().as_underlying_type()); - //printf("d2=%08ld %015ld\n", d2.imjd().as_underlying_type(), d2.sec().as_underlying_type()); - //printf("dt=(%d)%ld:%ld\n", interval.sign(), interval.days(), interval.sec().as_underlying_type()); - const auto d = d1 + interval; - assert( d == d2 ); + const auto interval = d2 - d1; + auto d = d1 + interval; + assert(d == d2); + const auto d32 = d3 - d2; + d = d2 + d32; + assert(d == d3); ++testnr; - } + if (testnr % 10) + printf("%d/%ld\r", testnr, num_tests); + } } return 0; diff --git a/test/unit_tests/interval.cpp b/test/unit_tests/interval.cpp index e1aac4a..8ec37f9 100644 --- a/test/unit_tests/interval.cpp +++ b/test/unit_tests/interval.cpp @@ -11,33 +11,33 @@ constexpr const SecIntType TOSEC = nsec::sec_factor(); int main() { - const auto i1 = datetime_interval(0,nsec(-1)); - assert(i1.days()==0); + const auto i1 = datetime_interval(0, nsec(-1)); + assert(i1.days() == 0); assert(i1.sec() == nsec(1)); assert(i1.sign() == -1); - - const auto i2 = datetime_interval(0,nsec(1)); - assert(i2.days()==0); + + const auto i2 = datetime_interval(0, nsec(1)); + assert(i2.days() == 0); assert(i2.sec() == nsec(1)); assert(i2.sign() == 1); - - const auto i3 = datetime_interval(1,nsec(1)); - assert(i3.days()==1); + + const auto i3 = datetime_interval(1, nsec(1)); + assert(i3.days() == 1); assert(i3.sec() == nsec(1)); assert(i3.sign() == 1); - - const auto i4 = datetime_interval(-1,nsec(1)); - assert(i4.days()==1); + + const auto i4 = datetime_interval(-1, nsec(1)); + assert(i4.days() == 1); assert(i4.sec() == nsec(1)); assert(i4.sign() == -1); - - const auto i5 = datetime_interval(nsec(-(86400*TOSEC+1))); - assert(i5.days()==1); + + const auto i5 = datetime_interval(nsec(-(86400 * TOSEC + 1))); + assert(i5.days() == 1); assert(i5.sec() == nsec(1)); assert(i5.sign() == -1); - - const auto i6 = datetime_interval(-1,nsec(-1)); - assert(i6.days()==1); + + const auto i6 = datetime_interval(-1, nsec(-1)); + assert(i6.days() == 1); assert(i6.sec() == nsec(1)); assert(i6.sign() == -1); diff --git a/test/unit_tests/mjd.cpp b/test/unit_tests/mjd.cpp index bbd00bc..60f0da0 100644 --- a/test/unit_tests/mjd.cpp +++ b/test/unit_tests/mjd.cpp @@ -1,7 +1,7 @@ #include "dtfund.hpp" #include -#include #include +#include using namespace dso; @@ -16,7 +16,7 @@ int main() { std::uniform_int_distribution<> mdstr(1, 12); /* range for months */ std::uniform_int_distribution<> ddstr(1, 31); /* range for day of month */ - for (long i=0; i using dso::day_of_month; +using dso::day_of_year; using dso::month; +using dso::ydoy_date; using dso::year; using dso::ymd_date; -using dso::ydoy_date; -using dso::day_of_year; int main() { @@ -27,7 +27,7 @@ int main() { ymd_date ymd(year(y), month(2), day_of_month(29)); assert(ymd.is_valid()); /* transform to Year - Day of Year */ - const ydoy_date ydoy (ymd); + const ydoy_date ydoy(ymd); assert((ydoy.yr() == year(y)) && (ydoy.dy() == day_of_year(31 + 29))); assert(ydoy.is_valid()); /* transform back to year/month/day of month */ @@ -42,8 +42,8 @@ int main() { assert(ydoy_date(ymd).dy() == day_of_year(366)); assert(ymd_date(ydoy_date(ymd)) == ymd); } else { - /* non-leap year, should not have a valid date for YYYY/02/29 but we - * should be able to create an invalid ydoy_date + /* non-leap year, should not have a valid date for YYYY/02/29 but we + * should be able to create an invalid ydoy_date */ ydoy_date iydoy(year(y), day_of_year(366)); /* which should be invalid */ @@ -51,7 +51,7 @@ int main() { /* and if we cast it to an ymd_date, it should throw */ try { ymd_date d5(iydoy); - assert(1==2); + assert(1 == 2); } catch (std::exception &) { ; } @@ -60,7 +60,7 @@ int main() { ymd_date vymd(year(y), month(2), day_of_month(28)); assert(vymd.is_valid()); /* transform to Year - Day of Year */ - const ydoy_date vydoy (vymd); + const ydoy_date vydoy(vymd); assert((vydoy.yr() == year(y)) && (vydoy.dy() == day_of_year(31 + 28))); assert(vydoy.is_valid()); } diff --git a/test/unit_tests/ymd_date.cpp b/test/unit_tests/ymd_date.cpp index 59cf628..abb2d3f 100644 --- a/test/unit_tests/ymd_date.cpp +++ b/test/unit_tests/ymd_date.cpp @@ -4,11 +4,11 @@ #include using dso::day_of_month; +using dso::day_of_year; using dso::month; +using dso::ydoy_date; using dso::year; using dso::ymd_date; -using dso::ydoy_date; -using dso::day_of_year; int main() { @@ -23,7 +23,7 @@ int main() { ymd_date ymd(year(y), month(2), day_of_month(29)); assert(ymd.is_valid()); /* transform to Year - Day of Year */ - const ydoy_date ydoy (ymd); + const ydoy_date ydoy(ymd); assert((ydoy.yr() == year(y)) && (ydoy.dy() == day_of_year(31 + 29))); assert(ydoy.is_valid()); /* extra checks */ @@ -36,8 +36,8 @@ int main() { /* non-leap year, should not have a valid date for YYYY/02/29 */ ymd_date iymd(year(y), month(2), day_of_month(29)); assert(!(iymd.is_valid())); - /* transform to Year - Day of Year; since this is an invalid date, the - * construction should throw! + /* transform to Year - Day of Year; since this is an invalid date, the + * construction should throw! */ try { const ydoy_date iydoy(iymd); @@ -50,7 +50,7 @@ int main() { ymd_date vymd(year(y), month(2), day_of_month(28)); assert(vymd.is_valid()); /* transform to Year - Day of Year */ - const ydoy_date vydoy (vymd); + const ydoy_date vydoy(vymd); assert((vydoy.yr() == year(y)) && (vydoy.dy() == day_of_year(31 + 28))); assert(vydoy.is_valid()); }