[Libreoffice-commits] core.git: include/svl svl/qa svl/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Fri Aug 31 10:51:18 UTC 2018


 include/svl/zformat.hxx        |    9 +
 svl/qa/unit/svl.cxx            |   22 +--
 svl/source/numbers/zformat.cxx |  227 ++++++++++++++++++++++-------------------
 3 files changed, 146 insertions(+), 112 deletions(-)

New commits:
commit e2e47898180e547cad7ccde1e5890385d573e551
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Fri Aug 31 11:21:03 2018 +0200
Commit:     Eike Rathke <erack at redhat.com>
CommitDate: Fri Aug 31 12:50:52 2018 +0200

    Use tools::Time::GetClock() in number formatter for wall clock time
    
    Also handle rounding/scaling better in ImpGetTimeOutput() for the
    [] duration formats, of which [HH]:MM:SS(.0000000) is used to edit
    time values.
    
    The wall clock change made it necessary to adapt some test cases in
    Test::testUserDefinedNumberFormats() where M_PI formatted to
    date+time actually is 1900-01-02 03:23:53.60527 with second 53
    instead of the previously rounded 54.
    
    Change-Id: I242a6c753a24281e041d3f73af019bdd77c65b37
    Reviewed-on: https://gerrit.libreoffice.org/59857
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins

diff --git a/include/svl/zformat.hxx b/include/svl/zformat.hxx
index 88b015f4adce..4f5dcb243ec5 100644
--- a/include/svl/zformat.hxx
+++ b/include/svl/zformat.hxx
@@ -700,6 +700,15 @@ private:
         return OUString::number(nVal);
     }
 
+    // Obtain the string of the fraction of second, without leading "0.",
+    // rounded to nFractionDecimals (or nFractionDecimals+1 if
+    // bAddOneRoundingDecimal==true but then truncated at nFractionDecimals,
+    // for use with the result of tools::Time::GetClock()) with the length of
+    // nFractionDecimals, unless nMinimumInputLineDecimals>0 is given for input
+    // line string where extra trailing "0" are discarded.
+    SVL_DLLPRIVATE sal_uInt16 ImpGetFractionOfSecondString( OUStringBuffer& rBuf, double fFractionOfSecond,
+            int nFractionDecimals, bool bAddOneRoundingDecimal, sal_uInt16 nIx, sal_uInt16 nMinimumInputLineDecimals );
+
     // transliterate according to NativeNumber
     SVL_DLLPRIVATE OUString impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum) const;
     SVL_DLLPRIVATE void impTransliterateImpl(OUStringBuffer& rStr, const SvNumberNatNum& rNum) const;
diff --git a/svl/qa/unit/svl.cxx b/svl/qa/unit/svl.cxx
index 68c4f15444a8..6824d15026fe 100644
--- a/svl/qa/unit/svl.cxx
+++ b/svl/qa/unit/svl.cxx
@@ -1285,12 +1285,12 @@ void Test::testUserDefinedNumberFormats()
     }
     {  // tdf#95339: detect SSMM as second minute
         sCode =     "SS:MM:HH DD/MM/YY"; // Month not detected by Excel, but we do not follow that.
-        sExpected = "54:23:03 02/01/00";
+        sExpected = "53:23:03 02/01/00";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
     }
     {  // tdf#101147: detect SSMM as second month
         sCode =     "HH:MM:SS MM/DD";
-        sExpected = "03:23:54 01/02";
+        sExpected = "03:23:53 01/02";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
     }
     {  // tdf#101096: different detection of month/minute with Excel
@@ -1301,7 +1301,7 @@ void Test::testUserDefinedNumberFormats()
         sExpected = "03:23 03 02/01";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "SS:DD-MM-YY SS:MM"; // 1st is month, because of previous DD; 2nd is minute as SS has not minute
-        sExpected = "54:02-01-00 54:23";
+        sExpected = "53:02-01-00 53:23";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
     }
     {  // tdf#99996: better algorithm for fraction representation
@@ -1475,49 +1475,49 @@ void Test::testUserDefinedNumberFormats()
     }
     {   // tdf#33689 use English NfKeywords in non-English language
         eLang = LANGUAGE_DUTCH;
-        sExpected = "Dutch: 1900/01/02 03:23:54";
+        sExpected = "Dutch: 1900/01/02 03:23:53";
         sCode =     "\"Dutch:\" JJJJ/MM/DD UU:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Dutch: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_GERMAN;
-        sExpected = "German: 1900/01/02 03:23:54";
+        sExpected = "German: 1900/01/02 03:23:53";
         sCode =     "\"German: \"JJJJ/MM/TT HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"German: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_FRENCH;
-        sExpected = "French: 1900/01/02 03:23:54";
+        sExpected = "French: 1900/01/02 03:23:53";
         sCode =     "\"French: \"AAAA/MM/JJ HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"French: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_ITALIAN;
-        sExpected = "Italian: 1900/01/02 03:23:54";
+        sExpected = "Italian: 1900/01/02 03:23:53";
         sCode =     "\"Italian: \"AAAA/MM/GG HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Italian: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_PORTUGUESE;
-        sExpected = "Portuguese: 1900/01/02 03:23:54";
+        sExpected = "Portuguese: 1900/01/02 03:23:53";
         sCode =     "\"Portuguese: \"AAAA/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Portuguese: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_SPANISH_MODERN;
-        sExpected = "Spanish: 1900/01/02 03:23:54";
+        sExpected = "Spanish: 1900/01/02 03:23:53";
         sCode =     "\"Spanish: \"AAAA/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Spanish: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_DANISH;
-        sExpected = "Danish: 1900/01/02 03:23:54";
+        sExpected = "Danish: 1900/01/02 03:23:53";
         sCode =     "\"Danish: \"YYYY/MM/DD TT:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Danish: \"YYYY/MM/DD HH:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         eLang = LANGUAGE_FINNISH;
-        sExpected = "Finnish: 1900/01/02 03:23:54";
+        sExpected = "Finnish: 1900/01/02 03:23:53";
         sCode =     "\"Finnish: \"VVVV/KK/PP TT:MM:SS";
         checkPreviewString(aFormatter, sCode, M_PI, eLang, sExpected);
         sCode =     "\"Finnish: \"YYYY/MM/DD HH:MM:SS";
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index cffa86176781..27d9b1322d5b 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -2940,6 +2940,37 @@ bool SvNumberformat::ImpGetFractionOutput(double fNumber,
     return bRes;
 }
 
+sal_uInt16 SvNumberformat::ImpGetFractionOfSecondString( OUStringBuffer& rBuf, double fFractionOfSecond,
+        int nFractionDecimals, bool bAddOneRoundingDecimal, sal_uInt16 nIx, sal_uInt16 nMinimumInputLineDecimals )
+{
+    if (!nFractionDecimals)
+        return 0;
+
+    // nFractionDecimals+1 to not round up what Time::GetClock() carefully
+    // truncated.
+    rBuf.append( rtl::math::doubleToUString( fFractionOfSecond, rtl_math_StringFormat_F,
+                (bAddOneRoundingDecimal ? nFractionDecimals + 1 : nFractionDecimals), '.'));
+    rBuf.stripStart('0');
+    rBuf.stripStart('.');
+    if (bAddOneRoundingDecimal && rBuf.getLength() > nFractionDecimals)
+        rBuf.truncate( nFractionDecimals); // the digit appended because of nFractionDecimals+1
+    if (nMinimumInputLineDecimals)
+    {
+        rBuf.stripEnd('0');
+        for (sal_Int32 index = rBuf.getLength(); index < nMinimumInputLineDecimals; ++index)
+        {
+            rBuf.append('0');
+        }
+        impTransliterate(rBuf, NumFor[nIx].GetNatNum());
+        nFractionDecimals = rBuf.getLength();
+    }
+    else
+    {
+        impTransliterate(rBuf, NumFor[nIx].GetNatNum());
+    }
+    return static_cast<sal_uInt16>(nFractionDecimals);
+}
+
 bool SvNumberformat::ImpGetTimeOutput(double fNumber,
                                       sal_uInt16 nIx,
                                       OUStringBuffer& sBuff)
@@ -2987,70 +3018,70 @@ bool SvNumberformat::ImpGetTimeOutput(double fNumber,
     {
         fNumber = 1.0 - fNumber; // "Inverse"
     }
-    double fTime = fNumber * 86400.0;
-    fTime = ::rtl::math::round( fTime, int(nCntPost) );
-    if (bSign && fTime == 0.0)
-    {
-        bSign = false; // Not -00:00:00
-    }
-    if( floor( fTime ) > D_MAX_U_INT32 )
-    {
-        sBuff = ImpSvNumberformatScan::GetErrorString();
-        return false;
-    }
-    sal_uInt32 nSeconds = static_cast<sal_uInt32>(floor( fTime ));
-
-    OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
-                                                          rtl_math_StringFormat_F, int(nCntPost), '.'));
-    sSecStr.stripStart('0');
-    sSecStr.stripStart('.');
-    if ( bInputLine )
-    {
-        sSecStr.stripEnd('0');
-        for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
-        {
-            sSecStr.append('0');
-        }
-        impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
-        nCntPost = sSecStr.getLength();
-    }
-    else
-    {
-        impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
-    }
 
+    OUStringBuffer sSecStr;
     sal_Int32 nSecPos = 0; // For figure by figure processing
     sal_uInt32 nHour, nMin, nSec;
     if (!rInfo.bThousand) // No [] format
     {
-        nHour = (nSeconds/3600) % 24;
-        nMin = (nSeconds%3600) / 60;
-        nSec = nSeconds%60;
-    }
-    else if (rInfo.nThousand == 3) // [ss]
-    {
-        nHour = 0;
-        nMin = 0;
-        nSec = nSeconds;
-    }
-    else if (rInfo.nThousand == 2) // [mm]:ss
-    {
-        nHour = 0;
-        nMin = nSeconds / 60;
-        nSec = nSeconds % 60;
-    }
-    else if (rInfo.nThousand == 1) // [hh]:mm:ss
-    {
-        nHour = nSeconds / 3600;
-        nMin = (nSeconds%3600) / 60;
-        nSec = nSeconds%60;
+        sal_uInt16 nCHour, nCMinute, nCSecond;
+        double fFractionOfSecond;
+        tools::Time::GetClock( fNumber, nCHour, nCMinute, nCSecond, fFractionOfSecond, nCntPost);
+        nHour = nCHour;
+        nMin = nCMinute;
+        nSec = nCSecond;
+        nCntPost = ImpGetFractionOfSecondString( sSecStr, fFractionOfSecond, nCntPost, true, nIx,
+                (bInputLine ? rInfo.nCntPost : 0));
     }
     else
     {
-        // TODO  What should these be set to?
-        nHour = 0;
-        nMin  = 0;
-        nSec  = 0;
+        double fTime = fNumber * 86400.0;
+        const double fOrigTime = fTime;
+        const double fFullSeconds = std::trunc(fTime);
+        fTime = rtl::math::round( fTime, int(nCntPost));
+        // Do not round up into the next magnitude, truncate instead.
+        if (fTime >= fFullSeconds + 1.0 || (fTime == 0.0 && fOrigTime != 0.0))
+            fTime = rtl::math::pow10Exp( std::trunc( rtl::math::pow10Exp( fOrigTime, nCntPost)), -nCntPost);
+
+        if (bSign && fTime == 0.0)
+        {
+            bSign = false; // Not -00:00:00
+        }
+        if (fTime > D_MAX_U_INT32)
+        {
+            sBuff = ImpSvNumberformatScan::GetErrorString();
+            return false;
+        }
+        sal_uInt32 nSeconds = static_cast<sal_uInt32>(fTime);
+
+        nCntPost = ImpGetFractionOfSecondString( sSecStr, fTime - nSeconds, nCntPost, false, nIx,
+                (bInputLine ? rInfo.nCntPost : 0));
+
+        if (rInfo.nThousand == 3) // [ss]
+        {
+            nHour = 0;
+            nMin = 0;
+            nSec = nSeconds;
+        }
+        else if (rInfo.nThousand == 2) // [mm]:ss
+        {
+            nHour = 0;
+            nMin = nSeconds / 60;
+            nSec = nSeconds % 60;
+        }
+        else if (rInfo.nThousand == 1) // [hh]:mm:ss
+        {
+            nHour = nSeconds / 3600;
+            nMin = (nSeconds%3600) / 60;
+            nSec = nSeconds%60;
+        }
+        else
+        {
+            // TODO  What should these be set to?
+            nHour = 0;
+            nMin  = 0;
+            nSec  = 0;
+        }
     }
 
     sal_Unicode cAmPm = ' '; // a or p
@@ -3873,57 +3904,51 @@ bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
     }
     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
 
-    sal_uInt32 nSeconds = static_cast<sal_uInt32>(floor( fTime ));
-    OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
-                                                  rtl_math_StringFormat_F, int(nCntPost), '.'));
-    sSecStr.stripStart('0');
-    sSecStr.stripStart('.');
-    if ( bInputLine )
-    {
-        sSecStr.stripEnd('0');
-        for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
-        {
-            sSecStr.append('0');
-        }
-        impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
-        nCntPost = sSecStr.getLength();
-    }
-    else
-    {
-        impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
-    }
-
+    OUStringBuffer sSecStr;
     sal_Int32 nSecPos = 0; // For figure by figure processing
     sal_uInt32 nHour, nMin, nSec;
-    if (!rInfo.bThousand) // [] format
-    {
-        nHour = (nSeconds/3600) % 24;
-        nMin = (nSeconds%3600) / 60;
-        nSec = nSeconds%60;
-    }
-    else if (rInfo.nThousand == 3) // [ss]
-    {
-        nHour = 0;
-        nMin = 0;
-        nSec = nSeconds;
-    }
-    else if (rInfo.nThousand == 2) // [mm]:ss
-    {
-        nHour = 0;
-        nMin = nSeconds / 60;
-        nSec = nSeconds % 60;
-    }
-    else if (rInfo.nThousand == 1) // [hh]:mm:ss
+    if (!rInfo.bThousand) // No [] format
     {
-        nHour = nSeconds / 3600;
-        nMin = (nSeconds%3600) / 60;
-        nSec = nSeconds%60;
+        sal_uInt16 nCHour, nCMinute, nCSecond;
+        double fFractionOfSecond;
+        tools::Time::GetClock( fNumber, nCHour, nCMinute, nCSecond, fFractionOfSecond, nCntPost);
+        nHour = nCHour;
+        nMin = nCMinute;
+        nSec = nCSecond;
+        nCntPost = ImpGetFractionOfSecondString( sSecStr, fFractionOfSecond, nCntPost, true, nIx,
+                (bInputLine ? rInfo.nCntPost : 0));
     }
     else
     {
-        nHour = 0;  // TODO What should these values be?
-        nMin  = 0;
-        nSec  = 0;
+        sal_uInt32 nSeconds = static_cast<sal_uInt32>(floor( fTime ));
+
+        nCntPost = ImpGetFractionOfSecondString( sSecStr, fTime - nSeconds, nCntPost, false, nIx,
+                (bInputLine ? rInfo.nCntPost : 0));
+
+        if (rInfo.nThousand == 3) // [ss]
+        {
+            nHour = 0;
+            nMin = 0;
+            nSec = nSeconds;
+        }
+        else if (rInfo.nThousand == 2) // [mm]:ss
+        {
+            nHour = 0;
+            nMin = nSeconds / 60;
+            nSec = nSeconds % 60;
+        }
+        else if (rInfo.nThousand == 1) // [hh]:mm:ss
+        {
+            nHour = nSeconds / 3600;
+            nMin = (nSeconds%3600) / 60;
+            nSec = nSeconds%60;
+        }
+        else
+        {
+            nHour = 0;  // TODO What should these values be?
+            nMin  = 0;
+            nSec  = 0;
+        }
     }
     sal_Unicode cAmPm = ' '; // a or p
     if (rInfo.nCntExp) // AM/PM


More information about the Libreoffice-commits mailing list