[Libreoffice-commits] core.git: Branch 'libreoffice-4-1' - scaddins/source

Lionel Elie Mamane lionel at mamane.lu
Wed Sep 18 03:53:27 PDT 2013


 scaddins/source/analysis/analysishelper.cxx |   72 ++++++++++++++++++++--------
 1 file changed, 52 insertions(+), 20 deletions(-)

New commits:
commit 0f002a14ecdc445deb2bc8d4cc6fbe4b724ac7f6
Author: Lionel Elie Mamane <lionel at mamane.lu>
Date:   Tue Sep 17 19:13:11 2013 +0200

    fdo#40100 make function YEARFRAC comply with ODF Version 1.2
    
    example of wrong result:
     =YEARFRAC(DATE(2023;1;1);DATE(2024;1;1);1)
    Pretty much by definition, this should be exactly 1,
    but it currently returns slightly less.
    
    Change-Id: I5ebb2ecde49dfca8a6191d2a7c11b9581669f455
    Reviewed-on: https://gerrit.libreoffice.org/5980
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>

diff --git a/scaddins/source/analysis/analysishelper.cxx b/scaddins/source/analysis/analysishelper.cxx
index 9c0095c..d84dc39 100644
--- a/scaddins/source/analysis/analysishelper.cxx
+++ b/scaddins/source/analysis/analysishelper.cxx
@@ -437,6 +437,7 @@ sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode )
 
 
 //fdo40100 toDo: make function fully compliant with ODFF1.2
+// LEM: I fixed case nMode==1; anything else to fix?
 /**
  * Function GetYearFrac implements YEARFRAC as defined in:
  *   Open Document Format for Office Applications version 1.2 Part 2, par. 6.10.24
@@ -522,7 +523,8 @@ double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDat
             break;
         case 1:         // 1=exact/exact
             {
-                bool isYearDifferent = ( nYear1 != nYear2 );
+                const bool isYearDifferent = ( nYear1 != nYear2 );
+                // ODFv1.2 part 2 section 4.11.7.7.7
                 if ( isYearDifferent &&
                      ( ( nYear2 != nYear1 + 1 ) ||
                        ( nMonth1 < nMonth2 ) ||
@@ -535,32 +537,62 @@ double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDat
 
                     nDaysInYear = ( double ) nDayCount / ( double ) ( nYear2 - nYear1 + 1 );
                 }
+                // we take advantage of the fact that (ODFv1.2 part 2) 4.11.7.7.9
+                // 4.11.7.7.10 can be permuted without changing the end result
+                // ODFv1.2 part 2 section 4.11.7.7.8 and 4.11.7.7.10
+                else if ( ( isYearDifferent && IsLeapYear( nYear1 ) ) ||
+                          ( nMonth2 == 2 && nDay2 == 29) )
+                {
+                    nDaysInYear = 366;
+                }
                 else
                 {
-                    if ( isYearDifferent && IsLeapYear( nYear1 ) )
+                    // ODFv1.2 part 2 section 4.11.7.7.9:
+                    // we need to determine whether there is a 29 February
+                    // between nDate1 and nDate2
+                    // LEM FIXME: I have a doubt concerning nDate1 == "29 February YYYY"
+                    //            In this case, is the "29 February YYYY" between nDate1 and nDate2
+                    //            in the meaning of ODFv1.2 part 2, section 4.11.7.7.9?
+                    //            I assume "no", since if "between" is to be understood as "inclusive"
+                    //            then 4.11.7.7.10 has no point.
+                    //            OTOH, it could theoretically be possible that "between"
+                    //            is to be understood as "inclusive the lower bound, exclusive in upper bound".
+
+                    assert(nYear1 == nYear2 || nYear1 + 1 == nYear2);
+                    // as a consequence, nYearDifferent iff nYear2 == nYear + 1, and
+                    // there are only two possible 29 Februaries to consider:
+                    // "29 February nYear1" and "29 February nYear2"
+
+                    // nDate2=="29 February YYYY" is handled above and the following conditions
+                    // rely on that for simplification.
+                    assert( ! (nMonth2 == 2 && nDay2 == 29));
+
+                    if( IsLeapYear( nYear1 ) )
+                       assert(nYear1 == nYear2);
+
+                    // is 29/2/nYear1 between nDate1 and nDate2?
+                    // that is only possible if IsLeapYear( nYear1 ),
+                    // which implies nYear1 == nYear2
+                    if( IsLeapYear( nYear1 ) &&
+                        ( nMonth1 == 1 || ( nMonth1 == 2 && nDay1 <= 28 )) &&
+                        nMonth2 > 2 )
+                    {
+                        nDaysInYear = 366;
+                    }
+                    // is 29/2/nYear2 between nDate1 and nDate2?
+                    // if nYear1==nYear2, then that is adequately tested by the previous test,
+                    // so no need to retest it here.
+                    else if(isYearDifferent && nMonth2 > 2 && IsLeapYear( nYear2 ))
                     {
                         nDaysInYear = 366;
                     }
                     else
                     {
-                        //if Feb 29 is between nDate1 and ndate2, inclusive
-                        if ( ( IsLeapYear( nYear1 ) && nMonth1 <= 2 && nDay1 <= 29 ) ||
-                             ( IsLeapYear( nYear2 ) && ( nMonth2 > 3 || ( nMonth2 == 2 && nDay1 == 29 ) ) ) )
-                        {
-                            nDaysInYear = 366;
-                        }
-                        else
-                        {
-                            nDaysInYear = 365;
-                            for ( sal_Int16 i = nYear1; i <= nYear2; i++ )
-                            {
-                                if ( IsLeapYear( i ) )
-                                {
-                                    nDaysInYear = 366;
-                                    break;
-                                }
-                            }
-                        }
+                        assert( !( IsLeapYear( nYear2 ) &&
+                                   nYear1 == nYear2 &&
+                                   (nMonth1 == 1 || (nMonth1==2 && nDay1 <= 28)) &&
+                                   nMonth2 > 2));
+                        nDaysInYear = 365;
                     }
                 }
             }


More information about the Libreoffice-commits mailing list