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)

Reply via email to