summaryrefslogtreecommitdiffstats
path: root/scaddins/source/datefunc
diff options
context:
space:
mode:
Diffstat (limited to 'scaddins/source/datefunc')
-rw-r--r--scaddins/source/datefunc/date.component26
-rw-r--r--scaddins/source/datefunc/datefunc.cxx760
-rw-r--r--scaddins/source/datefunc/datefunc.hxx198
-rw-r--r--scaddins/source/datefunc/deffuncname.hxx73
4 files changed, 1057 insertions, 0 deletions
diff --git a/scaddins/source/datefunc/date.component b/scaddins/source/datefunc/date.component
new file mode 100644
index 000000000..7bbf766a5
--- /dev/null
+++ b/scaddins/source/datefunc/date.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="date" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.sheet.addin.DateFunctionsImpl">
+ <service name="com.sun.star.sheet.AddIn"/>
+ <service name="com.sun.star.sheet.addin.DateFunctions"/>
+ </implementation>
+</component>
diff --git a/scaddins/source/datefunc/datefunc.cxx b/scaddins/source/datefunc/datefunc.cxx
new file mode 100644
index 000000000..f47b9b74a
--- /dev/null
+++ b/scaddins/source/datefunc/datefunc.cxx
@@ -0,0 +1,760 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "datefunc.hxx"
+#include <datefunc.hrc>
+#include <strings.hrc>
+#include <com/sun/star/util/Date.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <unotools/resmgr.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <algorithm>
+#include "deffuncname.hxx"
+
+using namespace ::com::sun::star;
+
+#define ADDIN_SERVICE "com.sun.star.sheet.AddIn"
+#define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions"
+#define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl"
+
+#define UNIQUE false // function name does not exist in Calc
+
+#define STDPAR false // all parameters are described
+#define INTPAR true // first parameter is internal
+
+#define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
+ { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
+
+const ScaFuncDataBase pFuncDataArr[] =
+{
+ FUNCDATA( DiffWeeks, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DiffMonths, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DiffYears, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( IsLeapYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DaysInMonth, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( DaysInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( WeeksInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
+ FUNCDATA( Rot13, 1, ScaCategory::Text, UNIQUE, STDPAR )
+};
+
+#undef FUNCDATA
+
+ScaFuncData::ScaFuncData(const ScaFuncDataBase& rBaseData) :
+ aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
+ pUINameID( rBaseData.pUINameID ),
+ pDescrID( rBaseData.pDescrID ),
+ nParamCount( rBaseData.nParamCount ),
+ eCat( rBaseData.eCat ),
+ bDouble( rBaseData.bDouble ),
+ bWithOpt( rBaseData.bWithOpt )
+{
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[0]));
+ aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[1]));
+}
+
+sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
+{
+ if( !bWithOpt )
+ nParam++;
+ return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
+}
+
+static void InitScaFuncDataList(ScaFuncDataList& rList)
+{
+ for (const auto & nIndex : pFuncDataArr)
+ rList.push_back(ScaFuncData(nIndex));
+}
+
+// entry points for service registration / instantiation
+static uno::Reference< uno::XInterface > ScaDateAddIn_CreateInstance(
+ const uno::Reference< lang::XMultiServiceFactory >& )
+{
+ return static_cast<cppu::OWeakObject*>(new ScaDateAddIn());
+}
+
+extern "C" {
+
+SAL_DLLPUBLIC_EXPORT void * date_component_getFactory(
+ const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
+{
+ void* pRet = nullptr;
+
+ if ( pServiceManager &&
+ OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
+ {
+ uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
+ static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
+ ScaDateAddIn::getImplementationName_Static(),
+ ScaDateAddIn_CreateInstance,
+ ScaDateAddIn::getSupportedServiceNames_Static() ) );
+
+ if (xFactory.is())
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ }
+
+ return pRet;
+}
+
+} // extern C
+
+// "normal" service implementation
+ScaDateAddIn::ScaDateAddIn()
+{
+}
+
+static const char* pLang[] = { "de", "en" };
+static const char* pCoun[] = { "DE", "US" };
+static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
+
+void ScaDateAddIn::InitDefLocales()
+{
+ pDefLocales.reset(new lang::Locale[ nNumOfLoc ]);
+
+ for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
+ {
+ pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
+ pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
+ }
+}
+
+const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
+{
+ if( !pDefLocales )
+ InitDefLocales();
+
+ return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
+}
+
+void ScaDateAddIn::InitData()
+{
+ aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
+ pFuncDataList.reset();
+
+ pFuncDataList.reset(new ScaFuncDataList);
+ InitScaFuncDataList(*pFuncDataList);
+
+ if( pDefLocales )
+ {
+ pDefLocales.reset();
+ }
+}
+
+OUString ScaDateAddIn::GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex)
+{
+ return ScaResId(pResId[nStrIndex - 1]);
+}
+
+OUString ScaDateAddIn::getImplementationName_Static()
+{
+ return MY_IMPLNAME;
+}
+
+uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
+{
+ return { ADDIN_SERVICE, MY_SERVICE };
+}
+
+// XServiceName
+OUString SAL_CALL ScaDateAddIn::getServiceName()
+{
+ // name of specific AddIn service
+ return MY_SERVICE;
+}
+
+// XServiceInfo
+OUString SAL_CALL ScaDateAddIn::getImplementationName()
+{
+ return getImplementationName_Static();
+}
+
+sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName )
+{
+ return cppu::supportsService(this, aServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames()
+{
+ return getSupportedServiceNames_Static();
+}
+
+// XLocalizable
+void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale )
+{
+ aFuncLoc = eLocale;
+ InitData(); // change of locale invalidates resources!
+}
+
+lang::Locale SAL_CALL ScaDateAddIn::getLocale()
+{
+ return aFuncLoc;
+}
+
+OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& )
+{
+ // not used by calc
+ // (but should be implemented for other uses of the AddIn service)
+ return OUString();
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ aRet = ScaResId(fDataIt->GetUINameID());
+ if( fDataIt->IsDouble() )
+ aRet += "_ADD";
+ }
+ else
+ {
+ aRet = "UNKNOWNFUNC_" + aProgrammaticName;
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 );
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr );
+ else
+ aRet = "internal";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
+ const OUString& aProgrammaticName, sal_Int32 nArgument )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
+ {
+ sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
+ if( nStr )
+ aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 );
+ else
+ aRet = "for internal use only";
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
+ const OUString& aProgrammaticName )
+{
+ OUString aRet;
+
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt != pFuncDataList->end() )
+ {
+ switch( fDataIt->GetCategory() )
+ {
+ case ScaCategory::DateTime: aRet = "Date&Time"; break;
+ case ScaCategory::Text: aRet = "Text"; break;
+ case ScaCategory::Finance: aRet = "Financial"; break;
+ case ScaCategory::Inf: aRet = "Information"; break;
+ case ScaCategory::Math: aRet = "Mathematical"; break;
+ case ScaCategory::Tech: aRet = "Technical"; break;
+ }
+ }
+
+ if( aRet.isEmpty() )
+ aRet = "Add-In";
+ return aRet;
+}
+
+OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
+ const OUString& aProgrammaticName )
+{
+ return getProgrammaticCategoryName( aProgrammaticName );
+}
+
+// XCompatibilityNames
+uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
+ const OUString& aProgrammaticName )
+{
+ auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
+ FindScaFuncData( aProgrammaticName ) );
+ if( fDataIt == pFuncDataList->end() )
+ return uno::Sequence< sheet::LocalizedName >( 0 );
+
+ const std::vector<OUString>& rStrList = fDataIt->GetCompNameList();
+ sal_uInt32 nCount = rStrList.size();
+
+ uno::Sequence< sheet::LocalizedName > aRet( nCount );
+ sheet::LocalizedName* pArray = aRet.getArray();
+
+ for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
+ pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList.at( nIndex ) );
+
+ return aRet;
+}
+
+namespace {
+
+// auxiliary functions
+bool IsLeapYear( sal_uInt16 nYear )
+{
+ return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
+}
+
+sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 };
+
+ if ( nMonth != 2 )
+ return aDaysInMonth[nMonth-1];
+ else
+ {
+ if ( IsLeapYear(nYear) )
+ return aDaysInMonth[nMonth-1] + 1;
+ else
+ return aDaysInMonth[nMonth-1];
+ }
+}
+
+/**
+ * Convert a date to a count of days starting from 01/01/0001
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts a Day , Month, Year representation
+ * to this internal Date value.
+ */
+
+sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
+{
+ sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365;
+ nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
+
+ for( sal_uInt16 i = 1; i < nMonth; i++ )
+ nDays += DaysInMonth(i,nYear);
+ nDays += nDay;
+
+ return nDays;
+}
+
+/**
+ * Convert a count of days starting from 01/01/0001 to a date
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function converts this internal Date value
+ * to a Day , Month, Year representation of a Date.
+ *
+ * @throws lang::IllegalArgumentException
+ */
+
+void DaysToDate( sal_Int32 nDays,
+ sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
+{
+ if( nDays < 0 )
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nTempDays;
+ sal_Int32 i = 0;
+ bool bCalc;
+
+ do
+ {
+ nTempDays = nDays;
+ rYear = static_cast<sal_uInt16>((nTempDays / 365) - i);
+ nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365;
+ nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
+ bCalc = false;
+ if ( nTempDays < 1 )
+ {
+ i++;
+ bCalc = true;
+ }
+ else
+ {
+ if ( nTempDays > 365 )
+ {
+ if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
+ {
+ i--;
+ bCalc = true;
+ }
+ }
+ }
+ }
+ while ( bCalc );
+
+ rMonth = 1;
+ while ( nTempDays > DaysInMonth( rMonth, rYear ) )
+ {
+ nTempDays -= DaysInMonth( rMonth, rYear );
+ rMonth++;
+ }
+ rDay = static_cast<sal_uInt16>(nTempDays);
+}
+
+/**
+ * Get the null date used by the spreadsheet document
+ *
+ * The internal representation of a Date used in this Addin
+ * is the number of days between 01/01/0001 and the date
+ * this function returns this internal Date value for the document null date
+ *
+ * @throws uno::RuntimeException
+ */
+sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
+{
+ if (xOptions.is())
+ {
+ try
+ {
+ uno::Any aAny = xOptions->getPropertyValue( "NullDate" );
+ util::Date aDate;
+ if ( aAny >>= aDate )
+ return DateToDays( aDate.Day, aDate.Month, aDate.Year );
+ }
+ catch (uno::Exception&)
+ {
+ }
+ }
+
+ // no null date available -> no calculations possible
+ throw uno::RuntimeException();
+}
+
+}
+// XDateFunctions
+
+/**
+ * Get week difference between 2 dates
+ *
+ * new Weeks(date1,date2,mode) function for StarCalc
+ *
+ * Two modes of operation are provided.
+ * The first is just a simple division by 7 calculation.
+ *
+ * The second calculates the difference by week of year.
+ *
+ * The International Standard IS-8601 has decreed that Monday
+ * shall be the first day of the week.
+ *
+ * A week that lies partly in one year and partly in another
+ * is assigned a number in the year in which most of its days lie.
+ *
+ * That means that week 1 of any year is the week that contains the 4. January
+ *
+ * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
+ *
+ * A WeekDay can be then calculated by subtracting 1 and calculating the rest of
+ * a division by 7, which gives a 0 - 6 value for Monday - Sunday
+ *
+ * Using the 4. January rule explained above the formula
+ *
+ * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
+ *
+ * calculates a number between 0-53 for each day which is in the same year as nJan4
+ * where 0 means that this week belonged to the year before.
+ *
+ * If a day in the same or another year is used in this formula this calculates
+ * a calendar week offset from a given 4. January
+ *
+ * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
+ *
+ * The 4.January of first Date Argument can thus be used to calculate
+ * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
+ *
+ * which can be optimized to
+ *
+ * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
+ *
+ * Note: All calculations are operating on the long integer data type
+ * % is the modulo operator in C which calculates the rest of an Integer division
+ *
+ *
+ * mode 0 is the interval between the dates in month, that is days / 7
+ *
+ * mode 1 is the difference by week of year
+ *
+ */
+
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if (nMode != 0 && nMode != 1)
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ sal_Int32 nDays1 = nStartDate + nNullDate;
+ sal_Int32 nDays2 = nEndDate + nNullDate;
+
+ sal_Int32 nRet;
+
+ if ( nMode == 1 )
+ {
+ sal_uInt16 nDay,nMonth,nYear;
+ DaysToDate( nDays1, nDay, nMonth, nYear );
+ sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
+
+ nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
+ }
+ else
+ {
+ nRet = (nDays2 - nDays1) / 7;
+ }
+ return nRet;
+}
+
+/**
+ * Get month difference between 2 dates
+ * =Month(start, end, mode) Function for StarCalc
+ *
+ * two modes are provided
+ *
+ * mode 0 is the interval between the dates in month
+ *
+ * mode 1 is the difference in calendar month
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if (nMode != 0 && nMode != 1)
+ throw lang::IllegalArgumentException();
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ sal_Int32 nDays1 = nStartDate + nNullDate;
+ sal_Int32 nDays2 = nEndDate + nNullDate;
+
+ sal_uInt16 nDay1,nMonth1,nYear1;
+ sal_uInt16 nDay2,nMonth2,nYear2;
+ DaysToDate(nDays1,nDay1,nMonth1,nYear1);
+ DaysToDate(nDays2,nDay2,nMonth2,nYear2);
+
+ sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
+ if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
+
+ if ( nDays1 < nDays2 )
+ {
+ if ( nDay1 > nDay2 )
+ {
+ nRet -= 1;
+ }
+ }
+ else
+ {
+ if ( nDay1 < nDay2 )
+ {
+ nRet += 1;
+ }
+ }
+
+ return nRet;
+}
+
+/**
+ * Get Year difference between 2 dates
+ *
+ * two modes are provided
+ *
+ * mode 0 is the interval between the dates in years
+ *
+ * mode 1 is the difference in calendar years
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nStartDate, sal_Int32 nEndDate,
+ sal_Int32 nMode )
+{
+ if (nMode != 0 && nMode != 1)
+ throw lang::IllegalArgumentException();
+
+ if ( nMode != 1 )
+ return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
+
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+
+ sal_Int32 nDays1 = nStartDate + nNullDate;
+ sal_Int32 nDays2 = nEndDate + nNullDate;
+
+ sal_uInt16 nDay1,nMonth1,nYear1;
+ sal_uInt16 nDay2,nMonth2,nYear2;
+ DaysToDate(nDays1,nDay1,nMonth1,nYear1);
+ DaysToDate(nDays2,nDay2,nMonth2,nYear2);
+
+ return nYear2 - nYear1;
+}
+
+/**
+ * Check if a Date is in a leap year in the Gregorian calendar
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return static_cast<sal_Int32>(IsLeapYear(nYear));
+}
+
+/**
+ * Get the Number of Days in the month for a date
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
+ const uno::Reference<beans::XPropertySet>& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return DaysInMonth( nMonth, nYear );
+}
+
+/**
+ * Get number of days in the year of a date specified
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ return ( IsLeapYear(nYear) ? 366 : 365 );
+}
+
+/**
+ * Get number of weeks in the year for a date
+ *
+ * Most years have 52 weeks, but years that start on a Thursday
+ * and leap years that start on a Wednesday have 53 weeks
+ *
+ * The International Standard IS-8601 has decreed that Monday
+ * shall be the first day of the week.
+ *
+ * A WeekDay can be calculated by subtracting 1 and calculating the rest of
+ * a division by 7 from the internal date representation
+ * which gives a 0 - 6 value for Monday - Sunday
+ *
+ * @see #IsLeapYear #WeekNumber
+ */
+sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
+ const uno::Reference< beans::XPropertySet >& xOptions,
+ sal_Int32 nDate )
+{
+ sal_Int32 nNullDate = GetNullDate( xOptions );
+ sal_Int32 nDays = nDate + nNullDate;
+
+ sal_uInt16 nDay, nMonth, nYear;
+ DaysToDate(nDays,nDay,nMonth,nYear);
+
+ sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
+
+ sal_Int32 nRet;
+ if ( nJan1WeekDay == 3 ) /* Thursday */
+ nRet = 53;
+ else if ( nJan1WeekDay == 2 ) /* Wednesday */
+ nRet = ( IsLeapYear(nYear) ? 53 : 52 );
+ else
+ nRet = 52;
+
+ return nRet;
+}
+
+/**
+ * Encrypt or decrypt a string using ROT13 algorithm
+ *
+ * This function rotates each character by 13 in the alphabet.
+ * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
+ */
+OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString )
+{
+ OUStringBuffer aBuffer( aSrcString );
+ for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
+ {
+ sal_Unicode cChar = aBuffer[nIndex];
+ if( (cChar >= 'a') && (cChar <= 'z'))
+ {
+ cChar += 13;
+ if (cChar > 'z')
+ cChar -= 26;
+ }
+ else if( (cChar >= 'A') && (cChar <= 'Z') )
+ {
+ cChar += 13;
+ if (cChar > 'Z')
+ cChar -= 26;
+ }
+ aBuffer[nIndex] = cChar;
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+OUString ScaDateAddIn::ScaResId(const char* pId)
+{
+ return Translate::get(pId, aResLocale);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/datefunc/datefunc.hxx b/scaddins/source/datefunc/datefunc.hxx
new file mode 100644
index 000000000..528a6d2f0
--- /dev/null
+++ b/scaddins/source/datefunc/datefunc.hxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// date functions add in
+
+#ifndef INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX
+#define INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX
+
+#include <vector>
+#include <memory>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sheet/XAddIn.hpp>
+#include <com/sun/star/sheet/XCompatibilityNames.hpp>
+#include <com/sun/star/sheet/addin/XDateFunctions.hpp>
+#include <com/sun/star/sheet/addin/XMiscFunctions.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+
+enum class ScaCategory
+{
+ DateTime,
+ Text,
+ Finance,
+ Inf,
+ Math,
+ Tech
+};
+
+struct ScaFuncDataBase
+{
+ const char* pIntName; // internal name (get***)
+ const char* pUINameID; // resource ID to UI name
+ const char** pDescrID; // resource ID to description, parameter names and ~ description
+ const char** pCompListID; // list of valid names
+ sal_uInt16 nParamCount; // number of named / described parameters
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+};
+
+class ScaFuncData final
+{
+private:
+ OUString aIntName; // internal name (get***)
+ const char* pUINameID; // resource ID to UI name
+ const char** pDescrID; // leads also to parameter descriptions!
+ sal_uInt16 nParamCount; // num of parameters
+ std::vector<OUString> aCompList; // list of all valid names
+ ScaCategory eCat; // function category
+ bool bDouble; // name already exist in Calc
+ bool bWithOpt; // first parameter is internal
+
+public:
+ ScaFuncData(const ScaFuncDataBase& rBaseData);
+
+ const char* GetUINameID() const { return pUINameID; }
+ const char** GetDescrID() const { return pDescrID; }
+ ScaCategory GetCategory() const { return eCat; }
+ bool IsDouble() const { return bDouble; }
+
+ sal_uInt16 GetStrIndex( sal_uInt16 nParam ) const;
+ bool Is( const OUString& rCompare ) const
+ { return aIntName == rCompare; }
+
+ const std::vector<OUString>& GetCompNameList() const { return aCompList; }
+};
+
+typedef std::vector<ScaFuncData> ScaFuncDataList;
+
+// Predicate for use with std::find_if
+struct FindScaFuncData
+{
+ const OUString& m_rId;
+ explicit FindScaFuncData( const OUString& rId ) : m_rId(rId) {}
+ bool operator() ( ScaFuncData const & rCandidate ) const { return rCandidate.Is(m_rId); }
+};
+
+
+css::uno::Reference< css::uno::XInterface > SAL_CALL DateFunctionAddIn_CreateInstance(
+ const css::uno::Reference< css::lang::XMultiServiceFactory >& );
+
+
+// THE AddIn class for date functions
+
+class ScaDateAddIn : public ::cppu::WeakImplHelper<
+ css::sheet::XAddIn,
+ css::sheet::XCompatibilityNames,
+ css::sheet::addin::XDateFunctions,
+ css::sheet::addin::XMiscFunctions,
+ css::lang::XServiceName,
+ css::lang::XServiceInfo >
+{
+private:
+ css::lang::Locale aFuncLoc;
+ std::unique_ptr< css::lang::Locale[] > pDefLocales;
+ std::locale aResLocale;
+ std::unique_ptr< ScaFuncDataList > pFuncDataList;
+
+
+ void InitDefLocales();
+ const css::lang::Locale& GetLocale( sal_uInt32 nIndex );
+ void InitData();
+
+ /// @throws css::uno::RuntimeException
+ OUString GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex);
+
+public:
+ ScaDateAddIn();
+
+ OUString ScaResId(const char* pId);
+
+ static OUString getImplementationName_Static();
+ static css::uno::Sequence< OUString > getSupportedServiceNames_Static();
+
+ // XAddIn
+ virtual OUString SAL_CALL getProgrammaticFuntionName( const OUString& aDisplayName ) override;
+ virtual OUString SAL_CALL getDisplayFunctionName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getFunctionDescription( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayArgumentName( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getArgumentDescription( const OUString& aProgrammaticName, sal_Int32 nArgument ) override;
+ virtual OUString SAL_CALL getProgrammaticCategoryName( const OUString& aProgrammaticName ) override;
+ virtual OUString SAL_CALL getDisplayCategoryName( const OUString& aProgrammaticName ) override;
+
+ // XCompatibilityNames
+ virtual css::uno::Sequence< css::sheet::LocalizedName > SAL_CALL getCompatibilityNames( const OUString& aProgrammaticName ) override;
+
+ // XLocalizable
+ virtual void SAL_CALL setLocale( const css::lang::Locale& eLocale ) override;
+ virtual css::lang::Locale SAL_CALL getLocale() override;
+
+ // XServiceName
+ virtual OUString SAL_CALL getServiceName() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // methods from own interfaces start here
+
+ // XDateFunctions
+ virtual sal_Int32 SAL_CALL getDiffWeeks(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getDiffMonths(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getDiffYears(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nEndDate, sal_Int32 nStartDate,
+ sal_Int32 nMode ) override;
+
+ virtual sal_Int32 SAL_CALL getIsLeapYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getDaysInMonth(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getDaysInYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ virtual sal_Int32 SAL_CALL getWeeksInYear(
+ const css::uno::Reference< css::beans::XPropertySet >& xOptions,
+ sal_Int32 nDate ) override;
+
+ // XMiscFunctions
+ virtual OUString SAL_CALL getRot13(
+ const OUString& aSrcText ) override;
+};
+
+#endif // INCLUDED_SCADDINS_SOURCE_DATEFUNC_DATEFUNC_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/scaddins/source/datefunc/deffuncname.hxx b/scaddins/source/datefunc/deffuncname.hxx
new file mode 100644
index 000000000..d1d807e3d
--- /dev/null
+++ b/scaddins/source/datefunc/deffuncname.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SCADDINS_SOURCE_DATEFUNC_DEFFUNCTIONNAME_HXX
+#define INCLUDED_SCADDINS_SOURCE_DATEFUNC_DEFFUNCTIONNAME_HXX
+
+static const char* DATE_DEFFUNCNAME_DiffWeeks[2] =
+{
+ "WOCHEN",
+ "WEEKS"
+};
+
+static const char* DATE_DEFFUNCNAME_DiffMonths[2] =
+{
+ "MONATE",
+ "MONTHS"
+};
+
+static const char* DATE_DEFFUNCNAME_DiffYears[2] =
+{
+ "JAHRE",
+ "YEARS"
+};
+
+static const char* DATE_DEFFUNCNAME_IsLeapYear[2] =
+{
+ "ISTSCHALTJAHR",
+ "ISLEAPYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_DaysInMonth[2] =
+{
+ "TAGEIMMONAT",
+ "DAYSINMONTH"
+};
+
+static const char* DATE_DEFFUNCNAME_DaysInYear[2] =
+{
+ "TAGEIMJAHR",
+ "DAYSINYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_WeeksInYear[2] =
+{
+ "WOCHENIMJAHR",
+ "WEEKSINYEAR"
+};
+
+static const char* DATE_DEFFUNCNAME_Rot13[2] =
+{
+ "ROT13",
+ "ROT13"
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */