include/tools/duration.hxx | 12 ++++++ tools/qa/cppunit/test_duration.cxx | 65 +++++++++++++++++++++++++++++++++- tools/source/datetime/duration.cxx | 70 +++++++++++++++++++++---------------- 3 files changed, 115 insertions(+), 32 deletions(-)
New commits: commit c968d8989004301b49d67a093a6eb8a629533837 Author: Eike Rathke <er...@redhat.com> AuthorDate: Fri Jun 23 12:42:29 2023 +0200 Commit: Eike Rathke <er...@redhat.com> CommitDate: Fri Jun 23 18:32:17 2023 +0200 Introduce tools::Duration individual time values ctor Change-Id: I516d3727cbcf6667b32dc963febbf4b753ef6a91 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153497 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins diff --git a/include/tools/duration.hxx b/include/tools/duration.hxx index a027cd671cd1..ea33953751b8 100644 --- a/include/tools/duration.hxx +++ b/include/tools/duration.hxx @@ -39,6 +39,14 @@ public: unless one is 0. */ Duration(sal_Int32 nDays, const Time& rTime); + /** Individual time values can be out-of-range, all will be normalized. + Additionally, the resulting time overall hour value is not restricted + to sal_uInt16 like it is with Time, as values >=24 flow over into days. + For a negative duration only a negative nDays can be given, thus a + negative duration of less than one day is not possible. */ + Duration(sal_Int32 nDays, sal_uInt32 nHours, sal_uInt32 nMinutes, sal_uInt32 nSeconds, + sal_uInt64 nNanoseconds); + bool IsNegative() const { return mnDays < 0 || maTime.GetTime() < 0; } sal_Int32 GetDays() const { return mnDays; } const Time& GetTime() const { return maTime; } @@ -60,6 +68,10 @@ private: /** Internal days and Time values. */ Duration(sal_Int32 nDays, sal_Int64 nTime); + /** Prerequisite: mnDays is already set. */ + void Normalize(sal_uInt64 nHours, sal_uInt64 nMinutes, sal_uInt64 nSeconds, + sal_uInt64 nNanoseconds, bool bNegative); + /** Prerequisite: mnDays is already correctly set and absolute value of nanoseconds less than one day. */ void ApplyTime(sal_Int64 nNS); diff --git a/tools/qa/cppunit/test_duration.cxx b/tools/qa/cppunit/test_duration.cxx index c328db7cec38..c4032be83a03 100644 --- a/tools/qa/cppunit/test_duration.cxx +++ b/tools/qa/cppunit/test_duration.cxx @@ -114,12 +114,73 @@ void DurationTest::testDuration() } { // 235929599 seconds == SAL_MAX_UINT16 hours + 59 minutes + 59 seconds - const Duration aD(0, Time(0, 0, 235929599)); + const Duration aD(0, Time(0, 0, 235929599, Time::nanoSecPerSec - 1)); CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2730), aD.GetDays()); CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(15), aD.GetTime().GetHour()); CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(59), aD.GetTime().GetMin()); CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(59), aD.GetTime().GetSec()); - CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), aD.GetTime().GetNanoSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(999999999), aD.GetTime().GetNanoSec()); + } + { + // 235929599 seconds == SAL_MAX_UINT16 hours + 59 minutes + 59 seconds + const Duration aD(0, 0, 0, 235929599, Time::nanoSecPerSec - 1); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2730), aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(15), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(59), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(59), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(999999999), aD.GetTime().GetNanoSec()); + } + { + const Duration aD(1, 2, 3, 4, 5); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(4), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(5), aD.GetTime().GetNanoSec()); + } + { + const Duration aD(-1, 2, 3, 4, 5); + CPPUNIT_ASSERT(aD.IsNegative()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1), aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(2), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(4), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(5), aD.GetTime().GetNanoSec()); + } + { + const Duration aD(1, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT64); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(182202802), aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(17), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(48), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(709551615), aD.GetTime().GetNanoSec()); + } + { + const Duration aD(-1, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT64); + CPPUNIT_ASSERT(aD.IsNegative()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-182202802), aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(17), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(48), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(709551615), aD.GetTime().GetNanoSec()); + } + { // Maximum days with all max possible. + const Duration aD(1965280846, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT32, + SAL_MAX_UINT64); + CPPUNIT_ASSERT_EQUAL(SAL_MAX_INT32, aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(17), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(48), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(709551615), aD.GetTime().GetNanoSec()); + } + { // Maximum negative days with all max possible. + const Duration aD(-1965280847, SAL_MAX_UINT32, SAL_MAX_UINT32, SAL_MAX_UINT32, + SAL_MAX_UINT64); + CPPUNIT_ASSERT_EQUAL(SAL_MIN_INT32, aD.GetDays()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), aD.GetTime().GetHour()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(17), aD.GetTime().GetMin()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(48), aD.GetTime().GetSec()); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(709551615), aD.GetTime().GetNanoSec()); } { // Add() const DateTime aS(Date(23, 11, 1999), Time(0, 0, 0)); diff --git a/tools/source/datetime/duration.cxx b/tools/source/datetime/duration.cxx index 255706f0486a..42ce2a8a6cc4 100644 --- a/tools/source/datetime/duration.cxx +++ b/tools/source/datetime/duration.cxx @@ -90,31 +90,47 @@ Duration::Duration(sal_Int32 nDays, const Time& rTime) : mnDays(nDays) { assert(nDays == 0 || rTime.GetTime() == 0 || (nDays < 0) == (rTime.GetTime() < 0)); - sal_uInt64 nN = rTime.GetNanoSec(); - sal_uInt64 nS = rTime.GetSec(); - if (nN >= Time::nanoSecPerSec) + Normalize(rTime.GetHour(), rTime.GetMin(), rTime.GetSec(), rTime.GetNanoSec(), + ((nDays < 0) || (rTime.GetTime() < 0))); +} + +Duration::Duration(sal_Int32 nDays, sal_uInt32 nHours, sal_uInt32 nMinutes, sal_uInt32 nSeconds, + sal_uInt64 nNanoseconds) + : mnDays(nDays) +{ + Normalize(nHours, nMinutes, nSeconds, nNanoseconds, nDays < 0); +} + +Duration::Duration(sal_Int32 nDays, sal_Int64 nTime) + : maTime(nTime) + , mnDays(nDays) +{ +} + +void Duration::Normalize(sal_uInt64 nHours, sal_uInt64 nMinutes, sal_uInt64 nSeconds, + sal_uInt64 nNanoseconds, bool bNegative) +{ + if (nNanoseconds >= Time::nanoSecPerSec) { - nS += nN / Time::nanoSecPerSec; - nN %= Time::nanoSecPerSec; + nSeconds += nNanoseconds / Time::nanoSecPerSec; + nNanoseconds %= Time::nanoSecPerSec; } - sal_uInt64 nM = rTime.GetMin(); - if (nS >= Time::secondPerMinute) + if (nSeconds >= Time::secondPerMinute) { - nM += nS / Time::secondPerMinute; - nS %= Time::secondPerMinute; + nMinutes += nSeconds / Time::secondPerMinute; + nSeconds %= Time::secondPerMinute; } - sal_uInt64 nH = rTime.GetHour(); - if (nM >= Time::minutePerHour) + if (nMinutes >= Time::minutePerHour) { - nH += nM / Time::minutePerHour; - nM %= Time::minutePerHour; + nHours += nMinutes / Time::minutePerHour; + nMinutes %= Time::minutePerHour; } - if (nH >= Time::hourPerDay) + if (nHours >= Time::hourPerDay) { - sal_Int64 nDiff = nH / Time::hourPerDay; - nH %= Time::hourPerDay; + sal_Int64 nDiff = nHours / Time::hourPerDay; + nHours %= Time::hourPerDay; bool bOverflow = false; - if (rTime.GetTime() < 0) + if (bNegative) { nDiff = -nDiff; bOverflow = (nDiff < SAL_MIN_INT32); @@ -132,24 +148,18 @@ Duration::Duration(sal_Int32 nDays, const Time& rTime) assert(!bOverflow); if (bOverflow) { - nH = Time::hourPerDay - 1; - nM = Time::minutePerHour - 1; - nS = Time::secondPerMinute - 1; - nN = Time::nanoSecPerSec - 1; + nHours = Time::hourPerDay - 1; + nMinutes = Time::minutePerHour - 1; + nSeconds = Time::secondPerMinute - 1; + nNanoseconds = Time::nanoSecPerSec - 1; } } - maTime = Time(nH, nM, nS, nN); - if (rTime.GetTime() < 0) + maTime = Time(nHours, nMinutes, nSeconds, nNanoseconds); + if (bNegative) maTime = -maTime; assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (maTime.GetTime() < 0)); } -Duration::Duration(sal_Int32 nDays, sal_Int64 nTime) - : maTime(nTime) - , mnDays(nDays) -{ -} - void Duration::ApplyTime(sal_Int64 nNS) { if (mnDays > 0 && nNS < 0) @@ -163,7 +173,7 @@ void Duration::ApplyTime(sal_Int64 nNS) nNS = -Time::nanoSecPerDay + nNS; } maTime.MakeTimeFromNS(nNS); - assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (nNS < 0)); + assert(mnDays == 0 || maTime.GetTime() == 0 || (mnDays < 0) == (maTime.GetTime() < 0)); } void Duration::SetTimeDiff(const Time& rStart, const Time& rEnd)