[Libreoffice-commits] core.git: include/tools sc/source tools/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Aug 28 14:24:17 UTC 2018


 include/tools/time.hxx           |   19 +++++++++++++
 sc/source/core/tool/interpr2.cxx |   56 ++++++---------------------------------
 tools/source/datetime/ttime.cxx  |   51 +++++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+), 47 deletions(-)

New commits:
commit 7f3c6efd859050c8f376b6820710e91fa9077ac4
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Tue Aug 28 13:46:37 2018 +0200
Commit:     Eike Rathke <erack at redhat.com>
CommitDate: Tue Aug 28 16:23:46 2018 +0200

    Move lcl_getHourMinuteSecond() to tools::Time::GetClock()
    
    Also add fFractionOfSecond and nFractionDecimals to obtain the
    remaining fraction of second.
    
    In preparation to use this in the number formatter and other
    places that obtain the wall clock time particles, which likely so
    far use bad rounding as well.
    
    Change-Id: I4fbea4165c560646438b06c340756c97dafa7c78
    Reviewed-on: https://gerrit.libreoffice.org/59700
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins

diff --git a/include/tools/time.hxx b/include/tools/time.hxx
index c6ada22a526d..9c137e5b9196 100644
--- a/include/tools/time.hxx
+++ b/include/tools/time.hxx
@@ -104,6 +104,25 @@ public:
                     /// 12 hours == 0.5 days
     double          GetTimeInDays() const;
 
+    /** Get the wall clock time particles for a (date+)time value.
+
+        Does the necessary rounding and truncating to obtain hour, minute,
+        second and fraction of second from a double time value (time in days,
+        0.5 == 12h) such that individual values are not rounded up, i.e.
+        x:59:59.999 does not yield x+1:0:0.00
+
+        A potential date component (fTimeInDays >= 1.0) is discarded.
+
+        @param  nFractionDecimals
+                If > 0 fFractionOfSecond is truncated to that amount of
+                decimals.
+                Else fFractionOfSecond returns the full remainder of the
+                fractional second.
+     */
+    static void     GetClock( double fTimeInDays,
+                              sal_uInt16& nHour, sal_uInt16& nMinute, sal_uInt16& nSecond,
+                              double& fFractionOfSecond, int nFractionDecimals );
+
     bool            IsEqualIgnoreNanoSec( const tools::Time& rTime ) const;
 
     bool            operator ==( const tools::Time& rTime ) const
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index 92bd4ebd1aae..6adc434a3864 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -142,65 +142,27 @@ void ScInterpreter::ScGetDay()
     PushDouble(static_cast<double>(aDate.GetDay()));
 }
 
-/* TODO: move this to tools::Time so also SvNumberFormatter and everything else
- * can use it and all display the same values. */
-static void lcl_getHourMinuteSecond( double fTimeInDays, sal_Int32& nHour, sal_Int32& nMinute, sal_Int32& nSecond )
-{
-    const double fTime = fTimeInDays - rtl::math::approxFloor(fTimeInDays); // date part absent
-
-    // If 0 then full day (or no day), shortcut.
-    // If < 0 then approxFloor() effectively returned the ceiling (note this
-    // also holds for negative fTimeInDays values) because of a near identical
-    // value, shortcut this to a full day as well.
-    // If >= 1.0 (actually == 1.0) then fTimeInDays is a negative small value
-    // not significant for a representable time and approxFloor() returned -1,
-    // shortcut to 0:0:0, otherwise it would become 24:0:0.
-    if (fTime <= 0.0 || fTime >= 1.0)
-    {
-        nHour = nMinute = nSecond = 0;
-        return;
-    }
-
-    // In seconds, including milli and nano.
-    const double fRawSeconds = fTime * DATE_TIME_FACTOR;
-
-    // Round to nanoseconds, which is the highest resolution this could be
-    // influenced by.
-    double fSeconds = rtl::math::round( fRawSeconds, 9);
-
-    // If this ended up as a full day the original value was very very close
-    // but not quite. Take that.
-    if (fSeconds >= tools::Time::secondPerDay)
-        fSeconds = fRawSeconds;
-
-    // Now do not round values (specifically not up), but truncate to the next
-    // magnitude, so 23:59:59.99 is still 23:59:59 and not 24:00:00 (or even
-    // 00:00:00 which Excel does).
-    nHour = fSeconds / tools::Time::secondPerHour;
-    fSeconds -= nHour * tools::Time::secondPerHour;
-    nMinute = fSeconds / tools::Time::secondPerMinute;
-    fSeconds -= nMinute * tools::Time::secondPerMinute;
-    nSecond = fSeconds;
-}
-
 void ScInterpreter::ScGetMin()
 {
-    sal_Int32 nHour, nMinute, nSecond;
-    lcl_getHourMinuteSecond( GetDouble(), nHour, nMinute, nSecond);
+    sal_uInt16 nHour, nMinute, nSecond;
+    double fFractionOfSecond;
+    tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
     PushDouble( nMinute);
 }
 
 void ScInterpreter::ScGetSec()
 {
-    sal_Int32 nHour, nMinute, nSecond;
-    lcl_getHourMinuteSecond( GetDouble(), nHour, nMinute, nSecond);
+    sal_uInt16 nHour, nMinute, nSecond;
+    double fFractionOfSecond;
+    tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
     PushDouble( nSecond);
 }
 
 void ScInterpreter::ScGetHour()
 {
-    sal_Int32 nHour, nMinute, nSecond;
-    lcl_getHourMinuteSecond( GetDouble(), nHour, nMinute, nSecond);
+    sal_uInt16 nHour, nMinute, nSecond;
+    double fFractionOfSecond;
+    tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
     PushDouble( nHour);
 }
 
diff --git a/tools/source/datetime/ttime.cxx b/tools/source/datetime/ttime.cxx
index a8b3a5d52b58..d9bfc40dfc02 100644
--- a/tools/source/datetime/ttime.cxx
+++ b/tools/source/datetime/ttime.cxx
@@ -39,6 +39,7 @@
 #endif
 
 #include <sal/log.hxx>
+#include <rtl/math.hxx>
 #include <tools/time.hxx>
 #include <osl/diagnose.h>
 
@@ -269,6 +270,56 @@ double tools::Time::GetTimeInDays() const
     return (nHour + (nMin / 60) + (nSec / (minInHour * secInMin)) + (nNanoSec / (minInHour * secInMin * nanoSecInSec))) / 24 * nSign;
 }
 
+// static
+void tools::Time::GetClock( double fTimeInDays,
+                            sal_uInt16& nHour, sal_uInt16& nMinute, sal_uInt16& nSecond,
+                            double& fFractionOfSecond, int nFractionDecimals )
+{
+    const double fTime = fTimeInDays - rtl::math::approxFloor(fTimeInDays); // date part absent
+
+    // If 0 then full day (or no day), shortcut.
+    // If < 0 then approxFloor() effectively returned the ceiling (note this
+    // also holds for negative fTimeInDays values) because of a near identical
+    // value, shortcut this to a full day as well.
+    // If >= 1.0 (actually == 1.0) then fTimeInDays is a negative small value
+    // not significant for a representable time and approxFloor() returned -1,
+    // shortcut to 0:0:0, otherwise it would become 24:0:0.
+    if (fTime <= 0.0 || fTime >= 1.0)
+    {
+        nHour = nMinute = nSecond = 0;
+        return;
+    }
+
+    // In seconds, including milli and nano.
+    const double fRawSeconds = fTime * tools::Time::secondPerDay;
+
+    // Round to nanoseconds, which is the highest resolution this could be
+    // influenced by.
+    double fSeconds = rtl::math::round( fRawSeconds, 9);
+
+    // If this ended up as a full day the original value was very very close
+    // but not quite. Take that.
+    if (fSeconds >= tools::Time::secondPerDay)
+        fSeconds = fRawSeconds;
+
+    // Now do not round values (specifically not up), but truncate to the next
+    // magnitude, so 23:59:59.99 is still 23:59:59 and not 24:00:00 (or even
+    // 00:00:00 which Excel does).
+    nHour = fSeconds / tools::Time::secondPerHour;
+    fSeconds -= nHour * tools::Time::secondPerHour;
+    nMinute = fSeconds / tools::Time::secondPerMinute;
+    fSeconds -= nMinute * tools::Time::secondPerMinute;
+    nSecond = fSeconds;
+    fSeconds -= nSecond;
+
+    // Do not round the fraction, otherwise .999 would end up as .00 again.
+    if (nFractionDecimals > 0)
+        fFractionOfSecond = rtl::math::pow10Exp( std::trunc(
+                    rtl::math::pow10Exp( fSeconds, nFractionDecimals)), -nFractionDecimals);
+    else
+        fFractionOfSecond = fSeconds;
+}
+
 Time& tools::Time::operator =( const tools::Time& rTime )
 {
     nTime = rTime.nTime;


More information about the Libreoffice-commits mailing list