diff options
author | Eike Rathke <erack@redhat.com> | 2023-08-03 20:52:43 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2023-08-03 21:42:53 +0200 |
commit | 46e672db8002e7aaac881bee65b5c50c4e14c666 (patch) | |
tree | 758f9727bc22b057dc4054d61c2dfc51316f31e5 | |
parent | 0b5e88bc88df6f0cd47e84cbd8bc53b649678f8b (diff) |
Resolves: tdf#127334 Increase tools::Duration accuracy epsilon unsharpness
... when converting from double, i.e. to 300 nanoseconds.
Empirically determined..
Change-Id: I92c43b5f244923363af5d44bece9c155126ca343
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155324
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
-rw-r--r-- | include/tools/duration.hxx | 13 | ||||
-rw-r--r-- | tools/source/datetime/duration.cxx | 25 |
2 files changed, 25 insertions, 13 deletions
diff --git a/include/tools/duration.hxx b/include/tools/duration.hxx index ea33953751b8..9fae80d1d7c9 100644 --- a/include/tools/duration.hxx +++ b/include/tools/duration.hxx @@ -31,8 +31,17 @@ public: minutes and seconds values here though. */ Duration(const Time& rStart, const Time& rEnd); - /** Difference in days, like DateTime()-DateTime(). */ - explicit Duration(double fTimeInDays); + /** Difference in days, like DateTime()-DateTime(). + + @param nAccuracyEpsilonNanoseconds + Round for example by 1 nanosecond if it's just 1 off to a + second, i.e. 0999999999 or 0000000001. This can be loosened if + necessary. For example, if fTimeInDays is a date+time in + "today's" range with a significant seconds resolution, an + accuracy epsilon (=unsharpness) of ~300 is required. Hence default. + Must be 0 <= nAccuracyEpsilonNanoseconds <= Time::nanoSecPerSec - 1. + */ + explicit Duration(double fTimeInDays, sal_uInt64 nAccuracyEpsilonNanoseconds = 300); /** 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 diff --git a/tools/source/datetime/duration.cxx b/tools/source/datetime/duration.cxx index a7b2762fff49..a655f016a1bc 100644 --- a/tools/source/datetime/duration.cxx +++ b/tools/source/datetime/duration.cxx @@ -47,8 +47,9 @@ Duration::Duration(const Time& rStart, const Time& rEnd) } } -Duration::Duration(double fTimeInDays) +Duration::Duration(double fTimeInDays, sal_uInt64 nAccuracyEpsilonNanoseconds) { + assert(nAccuracyEpsilonNanoseconds <= Time::nanoSecPerSec - 1); double fInt, fFrac; if (fTimeInDays < 0.0) { @@ -66,19 +67,21 @@ Duration::Duration(double fTimeInDays) fFrac *= Time::nanoSecPerDay; fFrac = ::rtl::math::approxFloor(fFrac); sal_Int64 nNS = static_cast<sal_Int64>(fFrac); - // Round by 1 nanosecond if it's just 1 off to a second, i.e. - // 0999999999 or 0000000001. This could be loosened to rounding by 2 or - // such if necessary. const sal_Int64 nN = nNS % Time::nanoSecPerSec; - if (std::abs(nN) == 1) - nNS -= (nNS < 0) ? -1 : 1; - else if (std::abs(nN) == Time::nanoSecPerSec - 1) + if (nN) { - nNS += (nNS < 0) ? -1 : 1; - if (std::abs(nNS) >= Time::nanoSecPerDay) + const sal_uInt64 nA = std::abs(nN); + if (nA <= nAccuracyEpsilonNanoseconds) + nNS -= (nNS < 0) ? -nN : nN; + else if (nA >= Time::nanoSecPerSec - nAccuracyEpsilonNanoseconds) { - mnDays += nNS / Time::nanoSecPerDay; - nNS %= Time::nanoSecPerDay; + const sal_Int64 nD = Time::nanoSecPerSec - nA; + nNS += (nNS < 0) ? -nD : nD; + if (std::abs(nNS) >= Time::nanoSecPerDay) + { + mnDays += nNS / Time::nanoSecPerDay; + nNS %= Time::nanoSecPerDay; + } } } maTime.MakeTimeFromNS(nNS); |