Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / scaddins / source / datefunc / datefunc.cxx
blob11c9e3da9f502403a54fbce866e0ae5388cd9dd7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 //------------------------------------------------------------------
31 // date functions add in
33 //------------------------------------------------------------------
35 #include "datefunc.hxx"
36 #include "datefunc.hrc"
37 #include <cppuhelper/factory.hxx>
38 #include <osl/diagnose.h>
39 #include <rtl/ustrbuf.hxx>
40 #include <tools/resmgr.hxx>
41 #include <tools/rcid.h>
42 #include <com/sun/star/util/Date.hpp>
44 using namespace ::com::sun::star;
45 using namespace ::rtl;
47 //------------------------------------------------------------------
49 #define ADDIN_SERVICE "com.sun.star.sheet.AddIn"
50 #define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions"
51 #define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl"
53 //------------------------------------------------------------------
55 #define STR_FROM_ANSI( s ) OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 )
57 //------------------------------------------------------------------
59 const sal_uInt32 ScaList::nStartSize = 16;
60 const sal_uInt32 ScaList::nIncrSize = 16;
62 ScaList::ScaList() :
63 pData( new void*[ nStartSize ] ),
64 nSize( nStartSize ),
65 nCount( 0 ),
66 nCurr( 0 )
70 ScaList::~ScaList()
72 delete[] pData;
75 void ScaList::_Grow()
77 nSize += nIncrSize;
79 void** pNewData = new void*[ nSize ];
80 memcpy( pNewData, pData, nCount * sizeof( void* ) );
82 delete[] pData;
83 pData = pNewData;
86 //------------------------------------------------------------------
88 ScaStringList::~ScaStringList()
90 for( OUString* pStr = First(); pStr; pStr = Next() )
91 delete pStr;
94 //------------------------------------------------------------------
96 ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) :
97 ResId( nId, rResMgr )
102 //------------------------------------------------------------------
104 #define UNIQUE sal_False // function name does not exist in Calc
105 #define DOUBLE sal_True // function name exists in Calc
107 #define STDPAR sal_False // all parameters are described
108 #define INTPAR sal_True // first parameter is internal
110 #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
111 { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
113 const ScaFuncDataBase pFuncDataArr[] =
115 FUNCDATA( DiffWeeks, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
116 FUNCDATA( DiffMonths, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
117 FUNCDATA( DiffYears, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
118 FUNCDATA( IsLeapYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
119 FUNCDATA( DaysInMonth, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
120 FUNCDATA( DaysInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
121 FUNCDATA( WeeksInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
122 FUNCDATA( Rot13, 1, ScaCat_Text, UNIQUE, STDPAR )
125 #undef FUNCDATA
128 //------------------------------------------------------------------
130 ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) :
131 aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
132 nUINameID( rBaseData.nUINameID ),
133 nDescrID( rBaseData.nDescrID ),
134 nCompListID( rBaseData.nCompListID ),
135 nParamCount( rBaseData.nParamCount ),
136 eCat( rBaseData.eCat ),
137 bDouble( rBaseData.bDouble ),
138 bWithOpt( rBaseData.bWithOpt )
140 ScaResStringArrLoader aArrLoader( RID_DATE_DEFFUNCTION_NAMES, nCompListID, rResMgr );
141 const ResStringArray& rArr = aArrLoader.GetStringArray();
143 for( sal_uInt16 nIndex = 0; nIndex < rArr.Count(); nIndex++ )
144 aCompList.Append( rArr.GetString( nIndex ) );
147 ScaFuncData::~ScaFuncData()
151 sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
153 if( !bWithOpt )
154 nParam++;
155 return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
159 //------------------------------------------------------------------
161 ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) :
162 nLast( 0xFFFFFFFF )
164 for( sal_uInt16 nIndex = 0; nIndex < SAL_N_ELEMENTS(pFuncDataArr); nIndex++ )
165 Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) );
168 ScaFuncDataList::~ScaFuncDataList()
170 for( ScaFuncData* pFData = First(); pFData; pFData = Next() )
171 delete pFData;
174 const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const
176 if( aLastName == rProgrammaticName )
177 return Get( nLast );
179 for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ )
181 const ScaFuncData* pCurr = Get( nIndex );
182 if( pCurr->Is( rProgrammaticName ) )
184 const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName;
185 const_cast< ScaFuncDataList* >( this )->nLast = nIndex;
186 return pCurr;
189 return NULL;
193 //------------------------------------------------------------------
195 ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) :
196 Resource( rResId )
198 rRet = String( ScaResId( nIndex, rResMgr ) );
199 FreeResource();
203 //------------------------------------------------------------------
205 // entry points for service registration / instantiation
207 //------------------------------------------------------------------
209 uno::Reference< uno::XInterface > SAL_CALL ScaDateAddIn_CreateInstance(
210 const uno::Reference< lang::XMultiServiceFactory >& )
212 static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new ScaDateAddIn();
213 return xInst;
217 //------------------------------------------------------------------------
219 extern "C" {
221 SAL_DLLPUBLIC_EXPORT void * SAL_CALL date_component_getFactory(
222 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
224 void* pRet = 0;
226 if ( pServiceManager &&
227 OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
229 uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
230 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ),
231 ScaDateAddIn::getImplementationName_Static(),
232 ScaDateAddIn_CreateInstance,
233 ScaDateAddIn::getSupportedServiceNames_Static() ) );
235 if (xFactory.is())
237 xFactory->acquire();
238 pRet = xFactory.get();
242 return pRet;
245 } // extern C
247 //------------------------------------------------------------------------
249 // "normal" service implementation
251 //------------------------------------------------------------------------
253 ScaDateAddIn::ScaDateAddIn() :
254 pDefLocales( NULL ),
255 pResMgr( NULL ),
256 pFuncDataList( NULL )
260 ScaDateAddIn::~ScaDateAddIn()
262 if( pFuncDataList )
263 delete pFuncDataList;
264 if( pDefLocales )
265 delete[] pDefLocales;
267 // pResMgr already deleted (_all_ resource managers are deleted _before_ this dtor is called)
270 static const sal_Char* pLang[] = { "de", "en" };
271 static const sal_Char* pCoun[] = { "DE", "US" };
272 static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
274 void ScaDateAddIn::InitDefLocales()
276 pDefLocales = new lang::Locale[ nNumOfLoc ];
278 for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
280 pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
281 pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
285 const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
287 if( !pDefLocales )
288 InitDefLocales();
290 return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
293 ResMgr& ScaDateAddIn::GetResMgr() throw( uno::RuntimeException )
295 if( !pResMgr )
297 InitData(); // try to get resource manager
298 if( !pResMgr )
299 throw uno::RuntimeException();
301 return *pResMgr;
304 void ScaDateAddIn::InitData()
306 if( pResMgr )
307 delete pResMgr;
309 OString aModName( "date" );
310 pResMgr = ResMgr::CreateResMgr( aModName.getStr(), aFuncLoc );
312 if( pFuncDataList )
313 delete pFuncDataList;
315 pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL;
317 if( pDefLocales )
319 delete pDefLocales;
320 pDefLocales = NULL;
324 OUString ScaDateAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException )
326 return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString();
329 OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException )
331 OUString aRet;
333 ScaResPublisher aResPubl( ScaResId( RID_DATE_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
334 ScaResId aResId( nResId, GetResMgr() );
335 aResId.SetRT( RSC_RESOURCE );
337 if( aResPubl.IsAvailableRes( aResId ) )
338 ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet );
340 aResPubl.FreeResource();
341 return aRet;
345 //------------------------------------------------------------------------
347 OUString ScaDateAddIn::getImplementationName_Static()
349 return OUString(RTL_CONSTASCII_USTRINGPARAM( MY_IMPLNAME ));
352 uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
354 uno::Sequence< OUString > aRet( 2 );
355 OUString* pArray = aRet.getArray();
356 pArray[0] = OUString(RTL_CONSTASCII_USTRINGPARAM( ADDIN_SERVICE ));
357 pArray[1] = OUString(RTL_CONSTASCII_USTRINGPARAM( MY_SERVICE ));
358 return aRet;
361 // XServiceName
363 OUString SAL_CALL ScaDateAddIn::getServiceName() throw( uno::RuntimeException )
365 // name of specific AddIn service
366 return OUString(RTL_CONSTASCII_USTRINGPARAM( MY_SERVICE ));
369 // XServiceInfo
371 OUString SAL_CALL ScaDateAddIn::getImplementationName() throw( uno::RuntimeException )
373 return getImplementationName_Static();
376 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException )
378 return aServiceName == ADDIN_SERVICE || aServiceName == MY_SERVICE;
381 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() throw( uno::RuntimeException )
383 return getSupportedServiceNames_Static();
386 // XLocalizable
388 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException )
390 aFuncLoc = eLocale;
391 InitData(); // change of locale invalidates resources!
394 lang::Locale SAL_CALL ScaDateAddIn::getLocale() throw( uno::RuntimeException )
396 return aFuncLoc;
399 //------------------------------------------------------------------
401 // function descriptions start here
403 //------------------------------------------------------------------
405 // XAddIn
407 OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException )
409 // not used by calc
410 // (but should be implemented for other uses of the AddIn service)
411 return OUString();
414 OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException )
416 OUString aRet;
418 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
419 if( pFData )
421 aRet = GetDisplFuncStr( pFData->GetUINameID() );
422 if( pFData->IsDouble() )
423 aRet += STR_FROM_ANSI( "_ADD" );
425 else
427 aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" );
428 aRet += aProgrammaticName;
431 return aRet;
434 OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException )
436 OUString aRet;
438 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
439 if( pFData )
440 aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 );
442 return aRet;
445 OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
446 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException )
448 OUString aRet;
450 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
451 if( pFData && (nArgument <= 0xFFFF) )
453 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
454 if( nStr )
455 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr );
456 else
457 aRet = STR_FROM_ANSI( "internal" );
460 return aRet;
463 OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
464 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException )
466 OUString aRet;
468 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
469 if( pFData && (nArgument <= 0xFFFF) )
471 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
472 if( nStr )
473 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 );
474 else
475 aRet = STR_FROM_ANSI( "for internal use only" );
478 return aRet;
481 OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
482 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
484 OUString aRet;
486 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
487 if( pFData )
489 switch( pFData->GetCategory() )
491 case ScaCat_DateTime: aRet = STR_FROM_ANSI( "Date&Time" ); break;
492 case ScaCat_Text: aRet = STR_FROM_ANSI( "Text" ); break;
493 case ScaCat_Finance: aRet = STR_FROM_ANSI( "Financial" ); break;
494 case ScaCat_Inf: aRet = STR_FROM_ANSI( "Information" ); break;
495 case ScaCat_Math: aRet = STR_FROM_ANSI( "Mathematical" ); break;
496 case ScaCat_Tech: aRet = STR_FROM_ANSI( "Technical" ); break;
497 default: // to prevent compiler warnings
498 break;
502 if( aRet.isEmpty() )
503 aRet = STR_FROM_ANSI( "Add-In" );
504 return aRet;
507 OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
508 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
510 return getProgrammaticCategoryName( aProgrammaticName );
514 // XCompatibilityNames
516 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
517 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
519 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
520 if( !pFData )
521 return uno::Sequence< sheet::LocalizedName >( 0 );
523 const ScaStringList& rStrList = pFData->GetCompNameList();
524 sal_uInt32 nCount = rStrList.Count();
526 uno::Sequence< sheet::LocalizedName > aRet( nCount );
527 sheet::LocalizedName* pArray = aRet.getArray();
529 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
530 pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) );
532 return aRet;
536 //------------------------------------------------------------------
538 // function implementation starts here
540 //------------------------------------------------------------------
542 // auxiliary functions
544 sal_Bool IsLeapYear( sal_uInt16 nYear )
546 return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
549 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
551 static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
552 31, 31, 30, 31, 30, 31 };
554 if ( nMonth != 2 )
555 return aDaysInMonth[nMonth-1];
556 else
558 if ( IsLeapYear(nYear) )
559 return aDaysInMonth[nMonth-1] + 1;
560 else
561 return aDaysInMonth[nMonth-1];
566 * Convert a date to a count of days starting from 01/01/0001
568 * The internal representation of a Date used in this Addin
569 * is the number of days between 01/01/0001 and the date
570 * this function converts a Day , Month, Year representation
571 * to this internal Date value.
574 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
576 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
577 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
579 for( sal_uInt16 i = 1; i < nMonth; i++ )
580 nDays += DaysInMonth(i,nYear);
581 nDays += nDay;
583 return nDays;
587 * Convert a count of days starting from 01/01/0001 to a date
589 * The internal representation of a Date used in this Addin
590 * is the number of days between 01/01/0001 and the date
591 * this function converts this internal Date value
592 * to a Day , Month, Year representation of a Date.
595 void DaysToDate( sal_Int32 nDays,
596 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
597 throw( lang::IllegalArgumentException )
599 if( nDays < 0 )
600 throw lang::IllegalArgumentException();
602 sal_Int32 nTempDays;
603 sal_Int32 i = 0;
604 sal_Bool bCalc;
608 nTempDays = nDays;
609 rYear = (sal_uInt16)((nTempDays / 365) - i);
610 nTempDays -= ((sal_Int32) rYear -1) * 365;
611 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
612 bCalc = sal_False;
613 if ( nTempDays < 1 )
615 i++;
616 bCalc = sal_True;
618 else
620 if ( nTempDays > 365 )
622 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
624 i--;
625 bCalc = sal_True;
630 while ( bCalc );
632 rMonth = 1;
633 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
635 nTempDays -= DaysInMonth( rMonth, rYear );
636 rMonth++;
638 rDay = (sal_uInt16)nTempDays;
642 * Get the null date used by the spreadsheet document
644 * The internal representation of a Date used in this Addin
645 * is the number of days between 01/01/0001 and the date
646 * this function returns this internal Date value for the document null date
650 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
651 throw( uno::RuntimeException )
653 if (xOptions.is())
657 uno::Any aAny = xOptions->getPropertyValue(
658 OUString(RTL_CONSTASCII_USTRINGPARAM( "NullDate" )) );
659 util::Date aDate;
660 if ( aAny >>= aDate )
661 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
663 catch (uno::Exception&)
668 // no null date available -> no calculations possible
669 throw uno::RuntimeException();
672 // XDateFunctions
675 * Get week difference between 2 dates
677 * new Weeks(date1,date2,mode) function for StarCalc
679 * Two modes of operation are provided.
680 * The first is just a simple division by 7 calculation.
682 * The second calculates the diffence by week of year.
684 * The International Standard IS-8601 has decreed that Monday
685 * shall be the first day of the week.
687 * A week that lies partly in one year and partly in annother
688 * is assigned a number in the the year in which most of its days lie.
690 * That means that week 1 of any year is the week that contains the 4. January
692 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
694 * A WeekDay can be then calculated by substracting 1 and calculating the rest of
695 * a division by 7, which gives a 0 - 6 value for Monday - Sunday
697 * Using the 4. January rule explained above the formula
699 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
701 * calculates a number between 0-53 for each day which is in the same year as nJan4
702 * where 0 means that this week belonged to the year before.
704 * If a day in the same or annother year is used in this formula this calculates
705 * an calendar week offset from a given 4. January
707 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
709 * The 4.January of first Date Argument can thus be used to calculate
710 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
712 * which can be optimized to
714 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
716 * Note: All calculations are operating on the long integer data type
717 * % is the modulo operator in C which calculates the rest of an Integer division
720 * mode 0 is the interval between the dates in month, that is days / 7
722 * mode 1 is the difference by week of year
726 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
727 const uno::Reference< beans::XPropertySet >& xOptions,
728 sal_Int32 nStartDate, sal_Int32 nEndDate,
729 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
731 sal_Int32 nNullDate = GetNullDate( xOptions );
733 sal_Int32 nDays1 = nStartDate + nNullDate;
734 sal_Int32 nDays2 = nEndDate + nNullDate;
736 sal_Int32 nRet;
738 if ( nMode == 1 )
740 sal_uInt16 nDay,nMonth,nYear;
741 DaysToDate( nDays1, nDay, nMonth, nYear );
742 sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
744 nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
746 else
748 nRet = (nDays2 - nDays1) / 7;
750 return nRet;
754 * Get month difference between 2 dates
755 * =Month(start, end, mode) Function for StarCalc
757 * two modes are provided
759 * mode 0 is the interval between the dates in month
761 * mode 1 is the difference in calendar month
764 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
765 const uno::Reference< beans::XPropertySet >& xOptions,
766 sal_Int32 nStartDate, sal_Int32 nEndDate,
767 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
769 sal_Int32 nNullDate = GetNullDate( xOptions );
771 sal_Int32 nDays1 = nStartDate + nNullDate;
772 sal_Int32 nDays2 = nEndDate + nNullDate;
774 sal_uInt16 nDay1,nMonth1,nYear1;
775 sal_uInt16 nDay2,nMonth2,nYear2;
776 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
777 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
779 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
780 if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
782 if ( nDays1 < nDays2 )
784 if ( nDay1 > nDay2 )
786 nRet -= 1;
789 else
791 if ( nDay1 < nDay2 )
793 nRet += 1;
797 return nRet;
801 * Get Year difference between 2 dates
803 * two modes are provided
805 * mode 0 is the interval between the dates in years
807 * mode 1 is the difference in calendar years
810 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
811 const uno::Reference< beans::XPropertySet >& xOptions,
812 sal_Int32 nStartDate, sal_Int32 nEndDate,
813 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
815 if ( nMode != 1 )
816 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
818 sal_Int32 nNullDate = GetNullDate( xOptions );
820 sal_Int32 nDays1 = nStartDate + nNullDate;
821 sal_Int32 nDays2 = nEndDate + nNullDate;
823 sal_uInt16 nDay1,nMonth1,nYear1;
824 sal_uInt16 nDay2,nMonth2,nYear2;
825 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
826 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
828 return nYear2 - nYear1;
832 * Check if a Date is in a leap year in the Gregorian calendar
835 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
836 const uno::Reference< beans::XPropertySet >& xOptions,
837 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
839 sal_Int32 nNullDate = GetNullDate( xOptions );
840 sal_Int32 nDays = nDate + nNullDate;
842 sal_uInt16 nDay, nMonth, nYear;
843 DaysToDate(nDays,nDay,nMonth,nYear);
845 return (sal_Int32)IsLeapYear(nYear);
849 * Get the Number of Days in the month for a date
852 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
853 const uno::Reference<beans::XPropertySet>& xOptions,
854 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
856 sal_Int32 nNullDate = GetNullDate( xOptions );
857 sal_Int32 nDays = nDate + nNullDate;
859 sal_uInt16 nDay, nMonth, nYear;
860 DaysToDate(nDays,nDay,nMonth,nYear);
862 return DaysInMonth( nMonth, nYear );
866 * Get number of days in the year of a date specified
869 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
870 const uno::Reference< beans::XPropertySet >& xOptions,
871 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
873 sal_Int32 nNullDate = GetNullDate( xOptions );
874 sal_Int32 nDays = nDate + nNullDate;
876 sal_uInt16 nDay, nMonth, nYear;
877 DaysToDate(nDays,nDay,nMonth,nYear);
879 return ( IsLeapYear(nYear) ? 366 : 365 );
883 * Get number of weeks in the year for a date
885 * Most years have 52 weeks, but years that start on a Thursday
886 * and leep years that start on a Wednesday have 53 weeks
888 * The International Standard IS-8601 has decreed that Monday
889 * shall be the first day of the week.
891 * A WeekDay can be calculated by substracting 1 and calculating the rest of
892 * a division by 7 from the internal date represention
893 * which gives a 0 - 6 value for Monday - Sunday
895 * @see #IsLeapYear #WeekNumber
898 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
899 const uno::Reference< beans::XPropertySet >& xOptions,
900 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
902 sal_Int32 nNullDate = GetNullDate( xOptions );
903 sal_Int32 nDays = nDate + nNullDate;
905 sal_uInt16 nDay, nMonth, nYear;
906 DaysToDate(nDays,nDay,nMonth,nYear);
908 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
910 sal_Int32 nRet;
911 if ( nJan1WeekDay == 3 ) /* Thursday */
912 nRet = 53;
913 else if ( nJan1WeekDay == 2 ) /* Wednesday */
914 nRet = ( IsLeapYear(nYear) ? 53 : 52 );
915 else
916 nRet = 52;
918 return nRet;
922 * Encrypt or decrypt a string using ROT13 algorithm
924 * This function rotates each character by 13 in the alphabet.
925 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
928 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) throw( uno::RuntimeException, lang::IllegalArgumentException )
930 OUStringBuffer aBuffer( aSrcString );
931 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
933 sal_Unicode cChar = aBuffer[nIndex];
934 if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) ||
935 ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) )
936 cChar -= 26;
937 aBuffer[nIndex] = cChar;
939 return aBuffer.makeStringAndClear();
942 //------------------------------------------------------------------
944 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */