summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tools/time.hxx19
-rw-r--r--sc/source/core/tool/interpr2.cxx56
-rw-r--r--tools/source/datetime/ttime.cxx51
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;