diff options
-rw-r--r-- | include/tools/time.hxx | 19 | ||||
-rw-r--r-- | sc/source/core/tool/interpr2.cxx | 56 | ||||
-rw-r--r-- | tools/source/datetime/ttime.cxx | 51 |
3 files changed, 79 insertions, 47 deletions
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; |