include/tools/duration.hxx         |    5 +++
 tools/qa/cppunit/test_duration.cxx |   17 ++++++++++
 tools/source/datetime/duration.cxx |   58 +++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

New commits:
commit 986c2d86a7b53a6599d014db7327f47cb33d4fea
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Wed Jun 21 21:56:56 2023 +0200
Commit:     Eike Rathke <er...@redhat.com>
CommitDate: Thu Jun 22 01:40:00 2023 +0200

    Introduce tools::Duration(sal_Int32 nDays, const Time& rTime) ctor
    
    Change-Id: If002e04536149b49b2249103ac914d17dec3fae6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153409
    Reviewed-by: Eike Rathke <er...@redhat.com>
    Tested-by: Jenkins

diff --git a/include/tools/duration.hxx b/include/tools/duration.hxx
index 83b9d12a77b3..a027cd671cd1 100644
--- a/include/tools/duration.hxx
+++ b/include/tools/duration.hxx
@@ -34,6 +34,11 @@ public:
     /** Difference in days, like DateTime()-DateTime(). */
     explicit Duration(double fTimeInDays);
 
+    /** Time can be a limited duration as well and can have out-of-range
+        values, it will be normalized. Sign of both days and Time must be equal
+        unless one is 0. */
+    Duration(sal_Int32 nDays, const Time& rTime);
+
     bool IsNegative() const { return mnDays < 0 || maTime.GetTime() < 0; }
     sal_Int32 GetDays() const { return mnDays; }
     const Time& GetTime() const { return maTime; }
diff --git a/tools/qa/cppunit/test_duration.cxx 
b/tools/qa/cppunit/test_duration.cxx
index 0f5a4e002219..c328db7cec38 100644
--- a/tools/qa/cppunit/test_duration.cxx
+++ b/tools/qa/cppunit/test_duration.cxx
@@ -104,6 +104,23 @@ void DurationTest::testDuration()
         const Duration aN = -aD;
         CPPUNIT_ASSERT_EQUAL(1.5, aN.GetInDays());
     }
+    {
+        const Duration aD(1, Time(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());
+    }
+    {
+        // 235929599 seconds == SAL_MAX_UINT16 hours + 59 minutes + 59 seconds
+        const Duration aD(0, Time(0, 0, 235929599));
+        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());
+    }
     { // Add()
         const DateTime aS(Date(23, 11, 1999), Time(0, 0, 0));
         const DateTime aE(Date(23, 11, 1999), Time(1, 23, 45));
diff --git a/tools/source/datetime/duration.cxx 
b/tools/source/datetime/duration.cxx
index 3aa195cfbda5..255706f0486a 100644
--- a/tools/source/datetime/duration.cxx
+++ b/tools/source/datetime/duration.cxx
@@ -86,6 +86,64 @@ Duration::Duration(double fTimeInDays)
     }
 }
 
+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)
+    {
+        nS += nN / Time::nanoSecPerSec;
+        nN %= Time::nanoSecPerSec;
+    }
+    sal_uInt64 nM = rTime.GetMin();
+    if (nS >= Time::secondPerMinute)
+    {
+        nM += nS / Time::secondPerMinute;
+        nS %= Time::secondPerMinute;
+    }
+    sal_uInt64 nH = rTime.GetHour();
+    if (nM >= Time::minutePerHour)
+    {
+        nH += nM / Time::minutePerHour;
+        nM %= Time::minutePerHour;
+    }
+    if (nH >= Time::hourPerDay)
+    {
+        sal_Int64 nDiff = nH / Time::hourPerDay;
+        nH %= Time::hourPerDay;
+        bool bOverflow = false;
+        if (rTime.GetTime() < 0)
+        {
+            nDiff = -nDiff;
+            bOverflow = (nDiff < SAL_MIN_INT32);
+            bOverflow |= o3tl::checked_add(mnDays, 
static_cast<sal_Int32>(nDiff), mnDays);
+            if (bOverflow)
+                mnDays = SAL_MIN_INT32;
+        }
+        else
+        {
+            bOverflow = (nDiff > SAL_MAX_INT32);
+            bOverflow |= o3tl::checked_add(mnDays, 
static_cast<sal_Int32>(nDiff), mnDays);
+            if (bOverflow)
+                mnDays = SAL_MAX_INT32;
+        }
+        assert(!bOverflow);
+        if (bOverflow)
+        {
+            nH = Time::hourPerDay - 1;
+            nM = Time::minutePerHour - 1;
+            nS = Time::secondPerMinute - 1;
+            nN = Time::nanoSecPerSec - 1;
+        }
+    }
+    maTime = Time(nH, nM, nS, nN);
+    if (rTime.GetTime() < 0)
+        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)

Reply via email to