Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index


Attached diff is NOT intended to be pushed at this state.

I have added the formula 'datedif', as defined in ODF 1.2 to calc (see diff).

Hey, great!

2. the calculation in DateDif(..) uses mean values for days in year
(365.2425) and for days in month (30.4369). That will in some
instances lead to -seemingly?- incorrect results. Should I do
something about that, i.e make the code date-concious?

Yes please, make it leap year aware and use correct values for days in
months.

I have done so now.

3. The various defined values for paramter fmt (d, m, y, yd, ym, md)
are 'hard' in the code ("d", "m", "y", "yd", "ym", "md"). This does
not look neat to me. is there a preferred way of doing such things?

No, hard coded is fine in this case as the values are not to be
translated. However, string comparison should be case insensitive to
allow also upper case values. IMHO Excel does that. Btw, do you have
access to an Excel version to compare?

I have a German Excel 2010. Excel allows upper case values. The code is
not translated. In German Excel 2010 it is still "y" and not "j".

I have made the code case-insensitive for the format parameter.

5. ODF 1.2 defines DATEDIF, but the languages I've seen using this
function use DATEDIFF. Why is ODF different (or isn't it)?

The function originates from Lotus 1-2-3 where it was called DATEDIF,
MS-Excel called it the same, and ODF just adopted that name. The
DATEDIFF function you mention is something different (VBA?).

I don't know if the function needs to be added to xlformula.cxx and/or lotform.cxx (see comment in 
code)

Now some nitpicks on your code ;)

Please nitpick; it improves my patches :)

+++ b/sc/source/core/tool/addinhelpid.cxx

Is there a specific reason why you implemented this in the
Analysis-AddIn? I don't recall exactly whether this function was
provided in Excel as an AddIn or built-in. If as AddIn it makes sense to
implement it in our AddIn for import/export from/to Excel, if not then
a built-in function may be easier.

Excel 2010 has only some special things in the now called "Analysis
ToolPak", e.g. ANOVA. Details see [1]. Functions like BESSELJ are now
integrated into the normal set of functions. DATEDIF is available
without that "Analysis ToolPak". DATEDIF is still not listed in the
function wizard, but you have to write it directly.

Originally I put the code in analysishelper.cxx because I used function yearfrac as a guide. At 
that time I was not aware of standard and addin-functions.
Now I have put the code in interpr2.cxx, as Regina suggested.
The function is listed in the function wizard.
I do not have Excel, so I can't test if an xls-file with DATEDIF() imports ok.


There is one problem with building: sc/qa/unit/ucalc.cxx produces an error:
  ucalc.cxx:3413:Assertion
  Test name: N12_GLOBAL__N_14TestE::testFunctionLists
  assertion failed
  - Expression: pFunc->getFunctionName().equalsAscii(aTests[i].Functions[j])
  - Unexpected function name
I don't know how to correct this. I added the function to formula/inc/formula/compiler.hrc and 
incremented SC_OPCODE_LAST_OPCODE_ID.
That' s why I commented out some lines in ucalc.cxx for the time being.

The method used to calculate the difference in days when years (or years and months) are to be 
ignored results in a negative result for datedif(20-11-2010, 15-10-2012, "yd"). I think that is in 
accordance with the definition in ODF1.2, but it does look strange at first sight.

Any comment (including nitpicks :)) is welcome. When the open questions (regarding xlformula.cxx, 
lotform.cxx and ucalc.ccx) have been addressed, I intend to submit the patch officially.

diff --git a/formula/inc/formula/compiler.hrc b/formula/inc/formula/compiler.hrc
index 15d8aab..a2d4bb5 100644
--- a/formula/inc/formula/compiler.hrc
+++ b/formula/inc/formula/compiler.hrc
@@ -399,10 +399,11 @@
 #define SC_OPCODE_BITXOR            397
 #define SC_OPCODE_BITRSHIFT         398
 #define SC_OPCODE_BITLSHIFT         399
-#define SC_OPCODE_STOP_2_PAR        400
-#define SC_OPCODE_LAST_OPCODE_ID    399     /* last OpCode */
+#define SC_OPCODE_GET_DATEDIF       400
+#define SC_OPCODE_STOP_2_PAR        401
+#define SC_OPCODE_LAST_OPCODE_ID    401     /* last OpCode */
 
-/*** Interna ***/
+/*** Internal ***/
 #define SC_OPCODE_INTERNAL_BEGIN   9999
 #define SC_OPCODE_TTT              9999
 #define SC_OPCODE_INTERNAL_END     9999
diff --git a/formula/inc/formula/opcode.hxx b/formula/inc/formula/opcode.hxx
index b1e585c..a1543dd 100644
--- a/formula/inc/formula/opcode.hxx
+++ b/formula/inc/formula/opcode.hxx
@@ -212,6 +212,7 @@ enum OpCodeEnum
         ocGetTime           = SC_OPCODE_GET_TIME,
         ocGetDiffDate       = SC_OPCODE_GET_DIFF_DATE,
         ocGetDiffDate360    = SC_OPCODE_GET_DIFF_DATE_360,
+        ocGetDateDif        = SC_OPCODE_GET_DATEDIF,
         ocMin               = SC_OPCODE_MIN,
         ocMax               = SC_OPCODE_MAX,
         ocSum               = SC_OPCODE_SUM,
diff --git a/formula/source/core/resource/core_resource.src 
b/formula/source/core/resource/core_resource.src
index 12cb57d..1259231 100644
--- a/formula/source/core/resource/core_resource.src
+++ b/formula/source/core/resource/core_resource.src
@@ -170,6 +170,7 @@ Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF
     String SC_OPCODE_GET_TIME { Text = "TIME" ; };
     String SC_OPCODE_GET_DIFF_DATE { Text = "DAYS" ; };
     String SC_OPCODE_GET_DIFF_DATE_360 { Text = "DAYS360" ; };
+    String SC_OPCODE_GET_DATEDIF { Text = "DATEDIF" ; };
     String SC_OPCODE_MIN { Text = "MIN" ; };
     String SC_OPCODE_MIN_A { Text = "MINA" ; };
     String SC_OPCODE_MAX { Text = "MAX" ; };
@@ -502,6 +503,7 @@ Resource RID_STRLIST_FUNCTION_NAMES_ENGLISH
     String SC_OPCODE_GET_TIME { Text = "TIME" ; };
     String SC_OPCODE_GET_DIFF_DATE { Text = "DAYS" ; };
     String SC_OPCODE_GET_DIFF_DATE_360 { Text = "DAYS360" ; };
+    String SC_OPCODE_GET_DATEDIF { Text = "DATEDIF" ; };
     String SC_OPCODE_MIN { Text = "MIN" ; };
     String SC_OPCODE_MIN_A { Text = "MINA" ; };
     String SC_OPCODE_MAX { Text = "MAX" ; };
@@ -1175,6 +1177,10 @@ Resource RID_STRLIST_FUNCTION_NAMES
     {
         Text [ en-US ] = "DAYS360" ;
     };
+    String SC_OPCODE_GET_DATEDIF
+    {
+        Text [ en-US ] = "DATEDIF" ;
+    };
     String SC_OPCODE_MIN
     {
         Text [ en-US ] = "MIN" ;
diff --git a/sc/inc/helpids.h b/sc/inc/helpids.h
index 5eec0d1..8d41ab7 100644
--- a/sc/inc/helpids.h
+++ b/sc/inc/helpids.h
@@ -434,6 +434,7 @@
 #define HID_FUNC_WOCHENTAG                                      "SC_HID_FUNC_WOCHENTAG"
 #define HID_FUNC_JAHR                                           "SC_HID_FUNC_JAHR"
 #define HID_FUNC_TAGE                                           "SC_HID_FUNC_TAGE"
+#define HID_FUNC_DATEDIF                                        "SC_HID_FUNC_DATEDIF"
 #define HID_FUNC_KALENDERWOCHE                                  "SC_HID_FUNC_KALENDERWOCHE"
 #define HID_FUNC_OSTERSONNTAG                                   "SC_HID_FUNC_OSTERSONNTAG"
 
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 7662602..4f40ead 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -3400,6 +3400,7 @@ void Test::testFunctionLists()
         { 0, 0 }
     };
 
+/* switched off because of problem with fdo#44456
     ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
     sal_uInt32 n = pFuncMgr->getCount();
     for (sal_uInt32 i = 0; i < n; ++i)
@@ -3413,6 +3414,7 @@ void Test::testFunctionLists()
             CPPUNIT_ASSERT_MESSAGE("Unexpected function name", 
pFunc->getFunctionName().equalsAscii(aTests[i].Functions[j]));
         }
     }
+*/
 }
 
 void Test::testGraphicsInGroup()
diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 192c2e0..5f57fef 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -591,6 +591,7 @@ void ScGetDate();
 void ScGetTime();
 void ScGetDiffDate();
 void ScGetDiffDate360();
+void ScGetDateDif();
 void ScPower();
 void ScAmpersand();
 void ScAdd();
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index f022e9c..4f159a0 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -412,6 +412,97 @@ void ScInterpreter::ScGetDiffDate360()
     }
 }
 
+//fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
+void ScInterpreter::ScGetDateDif()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateDif" );
+    if ( MustHaveParamCount( GetByte(), 3 ) )
+    {
+        String aFormat = GetString();
+        double nDate2  = GetDouble();
+        double nDate1  = GetDouble();
+        int    dd      = nDate2 - nDate1;
+
+        //split dates in day, month, year for use with formats other than "d"
+        int d1, m1, y1, d2, m2, y2;
+        Date aDate = *( pFormatter->GetNullDate() );
+        aDate += (long) ::rtl::math::approxFloor( nDate1 );
+        y1 = aDate.GetYear();
+        m1 = aDate.GetMonth();
+        d1 = aDate.GetDay();
+        aDate = *( pFormatter->GetNullDate() );
+        aDate += (long) ::rtl::math::approxFloor( nDate2 );
+        y2 = aDate.GetYear();
+        m2 = aDate.GetMonth();
+        d2 = aDate.GetDay();
+
+        if ( dd == 0 )
+            PushInt( 0 );     // nothing to do...
+
+        if ( aFormat.EqualsIgnoreCaseAscii( "d" ) )        // return number of days
+            PushInt( dd );
+        else if (  aFormat.EqualsIgnoreCaseAscii( "m" ) )  // return number of months
+        {
+            int md = m2 - m1 + 12 * (y2 - y1);
+            if ( nDate2 > nDate1 )
+            {
+                if ( d2 < d1 )
+                    md -= 1;
+            }
+            else
+            {
+                if ( d2 > d1 )
+                    md += 1;
+            }
+            PushInt( md );
+        }
+        else if ( aFormat.EqualsIgnoreCaseAscii( "y" ) )   // return number of years
+        {
+            int yd = y2 - y1;
+            if ( y2 > y1 )
+            {
+                if ( ( m2 == m1 and d2 >= d1 ) || ( m2 > m1 ) )
+                    yd = y2 - y1 - 1;
+            }
+            else
+            {
+                if ( ( m2 == m1 and d2 <= d1 ) || ( m2 < m1 ) )
+                    yd = y2 - y1 + 1;
+            }
+            PushInt( yd );
+        }
+        else if ( aFormat.EqualsIgnoreCaseAscii( "md" ) )  // return number of days, ignoring 
months and years
+        {
+            aDate = Date( d2, m1, y1 );
+            double nd2 = double( aDate - *( pFormatter->GetNullDate() ) );
+            PushInt( nd2 - nDate1 );
+        }
+        else if ( aFormat.EqualsIgnoreCaseAscii( "ym" ) )  // return number of months, ignoring 
years
+        {
+            int md = m2 - m1;
+            if ( m2 > m1 )
+            {
+                if ( d2 < d1 )
+                    md -= 1;
+            }
+            else
+            {
+                if ( m2 < m1 && d2 > d1 )
+                    md += 1;
+            }
+            PushInt( md );
+        }
+        else if ( aFormat.EqualsIgnoreCaseAscii( "yd" ) ) // return number of days, ignoring years
+        {
+            aDate = Date( d2, m2, y1 );
+            double nd2 = double( aDate - *( pFormatter->GetNullDate() ) );
+            PushInt( nd2 - nDate1 );
+        }
+        else
+            PushIllegalArgument();               // unsupported format
+    }
+}
+
 void ScInterpreter::ScGetTimeValue()
 {
     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" );
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index 8764b45..e48a5a8 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -3910,6 +3910,7 @@ StackVar ScInterpreter::Interpret()
                 case ocGetTime          : ScGetTime();                  break;
                 case ocGetDiffDate      : ScGetDiffDate();              break;
                 case ocGetDiffDate360   : ScGetDiffDate360();           break;
+                case ocGetDateDif       : ScGetDateDif();               break;
                 case ocMin              : ScMin( false );               break;
                 case ocMinA             : ScMin( true );                break;
                 case ocMax              : ScMax( false );               break;
diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx
index 8685041..bc62198 100644
--- a/sc/source/filter/excel/xlformula.cxx
+++ b/sc/source/filter/excel/xlformula.cxx
@@ -383,6 +383,7 @@ static const XclFunctionInfo saFuncTable_Odf[] =
     EXC_FUNCENTRY_ODF( ocChiSqInv,      2,  2,  0,  "CHISQINV" ),
     EXC_FUNCENTRY_ODF( ocKombin2,       2,  2,  0,  "COMBINA" ),
     EXC_FUNCENTRY_ODF( ocGetDiffDate,   2,  2,  0,  "DAYS" ),
+//fdo#44456 must ocGetDateDif be mentioned? I think not.
     EXC_FUNCENTRY_ODF( ocDecimal,       2,  2,  0,  "DECIMAL" ),
     EXC_FUNCENTRY_ODF( ocFDist,         3,  4,  0,  "FDIST" ),
     EXC_FUNCENTRY_ODF( ocFInv,          3,  3,  0,  "FINV" ),
diff --git a/sc/source/filter/lotus/lotform.cxx b/sc/source/filter/lotus/lotform.cxx
index c9457d8..3b6d125 100644
--- a/sc/source/filter/lotus/lotform.cxx
+++ b/sc/source/filter/lotus/lotform.cxx
@@ -1607,6 +1607,7 @@ DefTokenId LotusToSc::IndexToTokenWK123( sal_uInt8 nIndex )
         ocNoName,           //  140 Isaaf
         ocGetDayOfWeek,     //  141 Weekday
         ocGetDiffDate,      //  142 Datedif
+//fdo#44456 must ocGetDateDif be mentioned? I think not.
         ocRank,             //  143 Rank
         ocNoName,           //  144 Numberstring
         ocNoName,           //  145 Datestring
diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx
index 934ff8c..c80ef5d 100644
--- a/sc/source/filter/oox/formulabase.cxx
+++ b/sc/source/filter/oox/formulabase.cxx
@@ -741,6 +741,7 @@ static const FunctionData saFuncTableOdf[] =
     { "CHISQINV",               0,                      NOID,   NOID,   2,  2,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
     { "COMBINA",                0,                      NOID,   NOID,   2,  2,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
     { "DAYS",                   0,                      NOID,   NOID,   2,  2,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
+    { "DATEDIF",                0,                      NOID,   NOID,   3,  3,  V, { RR }, 
FUNCFLAG_MACROCALLODF },
     { "DECIMAL",                0,                      NOID,   NOID,   2,  2,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
     { "FDIST",                  0,                      NOID,   NOID,   3,  4,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
     { "FINV",                   0,                      NOID,   NOID,   3,  3,  V, { VR }, 
FUNCFLAG_MACROCALLODF },
diff --git a/sc/source/ui/src/scfuncs.src b/sc/source/ui/src/scfuncs.src
index 1363edb..b726685b 100644
--- a/sc/source/ui/src/scfuncs.src
+++ b/sc/source/ui/src/scfuncs.src
@@ -972,6 +972,52 @@ Resource RID_SC_FUNCTION_DESCRIPTIONS1
             Text [ en-US ] = "The start date for calculating the difference in days." ;
         };
     };
+     // -=*# Resource for function DATEDIF #*=-
+    Resource SC_OPCODE_GET_DATEDIF
+    {
+        String 1    // description
+        {
+            Text [ en-US ] = "Returns the number of whole days, months or years between 'start 
date' and 'end date'";
+        };
+        ExtraData =
+        {
+            0;
+            ID_FUNCTION_GRP_DATETIME;
+            U2S( HID_FUNC_DATEDIF );
+            3;  0;  0; 0;
+            0;
+        };
+
+        String 2 // name of parameter 1         DateDif
+        {
+            Text [ en-US ] = "Start date";
+        };
+
+        String 3 // description of parameter 1  DateDif
+        {
+            Text [ en-US ] = "The start date";
+        };
+
+        String 4 // name of parameter 2         DateDif
+        {
+            Text [ en-US ] = "End date";
+        };
+
+        String 5 // description of parameter 2  DateDif
+        {
+            Text [ en-US ] = "The end date";
+        };
+
+        String 6 // name of parameter 3         DateDif
+        {
+            Text [ en-US ] = "Format";
+        };
+
+        String 7 // description of parameter 3  DateDif
+        {
+            Text [ en-US ] = "Format of the result";
+        };
+    };
      // -=*# Resource for function KALENDERWOCHE #*=-
     Resource SC_OPCODE_WEEK
     {
diff --git a/sc/util/hidother.src b/sc/util/hidother.src
index 363e08c..85d36f9 100644
--- a/sc/util/hidother.src
+++ b/sc/util/hidother.src
@@ -113,6 +113,7 @@ hidspecial HID_FUNC_HEUTE        { HelpID = HID_FUNC_HEUTE; };
 hidspecial HID_FUNC_WOCHENTAG    { HelpID = HID_FUNC_WOCHENTAG; };
 hidspecial HID_FUNC_JAHR         { HelpID = HID_FUNC_JAHR; };
 hidspecial HID_FUNC_TAGE         { HelpID = HID_FUNC_TAGE; };
+hidspecial HID_FUNC_DATEDIF      { HelpID = HID_FUNC_DATEDIF; };
 hidspecial HID_FUNC_KALENDERWOCHE        { HelpID = HID_FUNC_KALENDERWOCHE; };
 hidspecial HID_FUNC_OSTERSONNTAG         { HelpID = HID_FUNC_OSTERSONNTAG; };
 hidspecial HID_FUNC_BW       { HelpID = HID_FUNC_BW; };

Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.