summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLionel Elie Mamane <lionel@mamane.lu>2013-09-17 19:13:11 +0200
committerEike Rathke <erack@redhat.com>2013-09-18 10:53:08 +0000
commit0f002a14ecdc445deb2bc8d4cc6fbe4b724ac7f6 (patch)
tree020f3f56403aa142081c29bae1312bc7270463a0
parent03a341775507502dd58598edc3fd805a8518550d (diff)
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@redhat.com> Tested-by: Eike Rathke <erack@redhat.com>
-rw-r--r--scaddins/source/analysis/analysishelper.cxx72
1 files changed, 52 insertions, 20 deletions
diff --git a/scaddins/source/analysis/analysishelper.cxx b/scaddins/source/analysis/analysishelper.cxx
index 9c0095c4498b..d84dc3908fdd 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;
}
}
}