update credits
[LibreOffice.git] / scaddins / source / datefunc / datefunc.cxx
blob8f016d6f23dc27c1d674b0ff85e25d25a53a4bab
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 //------------------------------------------------------------------
22 // date functions add in
24 //------------------------------------------------------------------
26 #include "datefunc.hxx"
27 #include "datefunc.hrc"
28 #include <cppuhelper/factory.hxx>
29 #include <osl/diagnose.h>
30 #include <rtl/ustrbuf.hxx>
31 #include <tools/resmgr.hxx>
32 #include <tools/rcid.h>
33 #include <com/sun/star/util/Date.hpp>
35 using namespace ::com::sun::star;
36 using namespace ::rtl;
38 //------------------------------------------------------------------
40 #define ADDIN_SERVICE "com.sun.star.sheet.AddIn"
41 #define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions"
42 #define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl"
44 //------------------------------------------------------------------
46 #define STR_FROM_ANSI( s ) OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 )
48 //------------------------------------------------------------------
50 const sal_uInt32 ScaList::nStartSize = 16;
51 const sal_uInt32 ScaList::nIncrSize = 16;
53 ScaList::ScaList() :
54 pData( new void*[ nStartSize ] ),
55 nSize( nStartSize ),
56 nCount( 0 ),
57 nCurr( 0 )
61 ScaList::~ScaList()
63 delete[] pData;
66 void ScaList::_Grow()
68 nSize += nIncrSize;
70 void** pNewData = new void*[ nSize ];
71 memcpy( pNewData, pData, nCount * sizeof( void* ) );
73 delete[] pData;
74 pData = pNewData;
77 //------------------------------------------------------------------
79 ScaStringList::~ScaStringList()
81 for( OUString* pStr = First(); pStr; pStr = Next() )
82 delete pStr;
85 //------------------------------------------------------------------
87 ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) :
88 ResId( nId, rResMgr )
93 //------------------------------------------------------------------
95 #define UNIQUE sal_False // function name does not exist in Calc
97 #define STDPAR sal_False // all parameters are described
98 #define INTPAR sal_True // first parameter is internal
100 #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
101 { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
103 const ScaFuncDataBase pFuncDataArr[] =
105 FUNCDATA( DiffWeeks, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
106 FUNCDATA( DiffMonths, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
107 FUNCDATA( DiffYears, 3, ScaCat_DateTime, UNIQUE, INTPAR ),
108 FUNCDATA( IsLeapYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
109 FUNCDATA( DaysInMonth, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
110 FUNCDATA( DaysInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
111 FUNCDATA( WeeksInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ),
112 FUNCDATA( Rot13, 1, ScaCat_Text, UNIQUE, STDPAR )
115 #undef FUNCDATA
118 //------------------------------------------------------------------
120 ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) :
121 aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
122 nUINameID( rBaseData.nUINameID ),
123 nDescrID( rBaseData.nDescrID ),
124 nCompListID( rBaseData.nCompListID ),
125 nParamCount( rBaseData.nParamCount ),
126 eCat( rBaseData.eCat ),
127 bDouble( rBaseData.bDouble ),
128 bWithOpt( rBaseData.bWithOpt )
130 ScaResStringArrLoader aArrLoader( RID_DATE_DEFFUNCTION_NAMES, nCompListID, rResMgr );
131 const ResStringArray& rArr = aArrLoader.GetStringArray();
133 for( sal_uInt16 nIndex = 0; nIndex < rArr.Count(); nIndex++ )
134 aCompList.Append( rArr.GetString( nIndex ) );
137 ScaFuncData::~ScaFuncData()
141 sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
143 if( !bWithOpt )
144 nParam++;
145 return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
149 //------------------------------------------------------------------
151 ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) :
152 nLast( 0xFFFFFFFF )
154 for( sal_uInt16 nIndex = 0; nIndex < SAL_N_ELEMENTS(pFuncDataArr); nIndex++ )
155 Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) );
158 ScaFuncDataList::~ScaFuncDataList()
160 for( ScaFuncData* pFData = First(); pFData; pFData = Next() )
161 delete pFData;
164 const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const
166 if( aLastName == rProgrammaticName )
167 return Get( nLast );
169 for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ )
171 const ScaFuncData* pCurr = Get( nIndex );
172 if( pCurr->Is( rProgrammaticName ) )
174 const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName;
175 const_cast< ScaFuncDataList* >( this )->nLast = nIndex;
176 return pCurr;
179 return NULL;
183 //------------------------------------------------------------------
185 ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) :
186 Resource( rResId )
188 rRet = String( ScaResId( nIndex, rResMgr ) );
189 FreeResource();
193 //------------------------------------------------------------------
195 // entry points for service registration / instantiation
197 //------------------------------------------------------------------
199 uno::Reference< uno::XInterface > SAL_CALL ScaDateAddIn_CreateInstance(
200 const uno::Reference< lang::XMultiServiceFactory >& )
202 static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new ScaDateAddIn();
203 return xInst;
207 //------------------------------------------------------------------------
209 extern "C" {
211 SAL_DLLPUBLIC_EXPORT void * SAL_CALL date_component_getFactory(
212 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
214 void* pRet = 0;
216 if ( pServiceManager &&
217 OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
219 uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
220 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ),
221 ScaDateAddIn::getImplementationName_Static(),
222 ScaDateAddIn_CreateInstance,
223 ScaDateAddIn::getSupportedServiceNames_Static() ) );
225 if (xFactory.is())
227 xFactory->acquire();
228 pRet = xFactory.get();
232 return pRet;
235 } // extern C
237 //------------------------------------------------------------------------
239 // "normal" service implementation
241 //------------------------------------------------------------------------
243 ScaDateAddIn::ScaDateAddIn() :
244 pDefLocales( NULL ),
245 pResMgr( NULL ),
246 pFuncDataList( NULL )
250 ScaDateAddIn::~ScaDateAddIn()
252 if( pFuncDataList )
253 delete pFuncDataList;
254 if( pDefLocales )
255 delete[] pDefLocales;
257 // pResMgr already deleted (_all_ resource managers are deleted _before_ this dtor is called)
260 static const sal_Char* pLang[] = { "de", "en" };
261 static const sal_Char* pCoun[] = { "DE", "US" };
262 static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
264 void ScaDateAddIn::InitDefLocales()
266 pDefLocales = new lang::Locale[ nNumOfLoc ];
268 for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
270 pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
271 pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
275 const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
277 if( !pDefLocales )
278 InitDefLocales();
280 return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
283 ResMgr& ScaDateAddIn::GetResMgr() throw( uno::RuntimeException )
285 if( !pResMgr )
287 InitData(); // try to get resource manager
288 if( !pResMgr )
289 throw uno::RuntimeException();
291 return *pResMgr;
294 void ScaDateAddIn::InitData()
296 if( pResMgr )
297 delete pResMgr;
299 OString aModName( "date" );
300 pResMgr = ResMgr::CreateResMgr( aModName.getStr(), LanguageTag( aFuncLoc) );
302 if( pFuncDataList )
303 delete pFuncDataList;
305 pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL;
307 if( pDefLocales )
309 delete pDefLocales;
310 pDefLocales = NULL;
314 OUString ScaDateAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException )
316 return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString();
319 OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException )
321 OUString aRet;
323 ScaResPublisher aResPubl( ScaResId( RID_DATE_FUNCTION_DESCRIPTIONS, GetResMgr() ) );
324 ScaResId aResId( nResId, GetResMgr() );
325 aResId.SetRT( RSC_RESOURCE );
327 if( aResPubl.IsAvailableRes( aResId ) )
328 ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet );
330 aResPubl.FreeResource();
331 return aRet;
335 //------------------------------------------------------------------------
337 OUString ScaDateAddIn::getImplementationName_Static()
339 return OUString( MY_IMPLNAME );
342 uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
344 uno::Sequence< OUString > aRet( 2 );
345 OUString* pArray = aRet.getArray();
346 pArray[0] = OUString( ADDIN_SERVICE );
347 pArray[1] = OUString( MY_SERVICE );
348 return aRet;
351 // XServiceName
353 OUString SAL_CALL ScaDateAddIn::getServiceName() throw( uno::RuntimeException )
355 // name of specific AddIn service
356 return OUString( MY_SERVICE );
359 // XServiceInfo
361 OUString SAL_CALL ScaDateAddIn::getImplementationName() throw( uno::RuntimeException )
363 return getImplementationName_Static();
366 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException )
368 return aServiceName == ADDIN_SERVICE || aServiceName == MY_SERVICE;
371 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() throw( uno::RuntimeException )
373 return getSupportedServiceNames_Static();
376 // XLocalizable
378 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException )
380 aFuncLoc = eLocale;
381 InitData(); // change of locale invalidates resources!
384 lang::Locale SAL_CALL ScaDateAddIn::getLocale() throw( uno::RuntimeException )
386 return aFuncLoc;
389 //------------------------------------------------------------------
391 // function descriptions start here
393 //------------------------------------------------------------------
395 // XAddIn
397 OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException )
399 // not used by calc
400 // (but should be implemented for other uses of the AddIn service)
401 return OUString();
404 OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException )
406 OUString aRet;
408 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
409 if( pFData )
411 aRet = GetDisplFuncStr( pFData->GetUINameID() );
412 if( pFData->IsDouble() )
413 aRet += STR_FROM_ANSI( "_ADD" );
415 else
417 aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" );
418 aRet += aProgrammaticName;
421 return aRet;
424 OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException )
426 OUString aRet;
428 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
429 if( pFData )
430 aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 );
432 return aRet;
435 OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
436 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException )
438 OUString aRet;
440 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
441 if( pFData && (nArgument <= 0xFFFF) )
443 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
444 if( nStr )
445 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr );
446 else
447 aRet = STR_FROM_ANSI( "internal" );
450 return aRet;
453 OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
454 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException )
456 OUString aRet;
458 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
459 if( pFData && (nArgument <= 0xFFFF) )
461 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
462 if( nStr )
463 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 );
464 else
465 aRet = STR_FROM_ANSI( "for internal use only" );
468 return aRet;
471 OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
472 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
474 OUString aRet;
476 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
477 if( pFData )
479 switch( pFData->GetCategory() )
481 case ScaCat_DateTime: aRet = STR_FROM_ANSI( "Date&Time" ); break;
482 case ScaCat_Text: aRet = STR_FROM_ANSI( "Text" ); break;
483 case ScaCat_Finance: aRet = STR_FROM_ANSI( "Financial" ); break;
484 case ScaCat_Inf: aRet = STR_FROM_ANSI( "Information" ); break;
485 case ScaCat_Math: aRet = STR_FROM_ANSI( "Mathematical" ); break;
486 case ScaCat_Tech: aRet = STR_FROM_ANSI( "Technical" ); break;
487 default: // to prevent compiler warnings
488 break;
492 if( aRet.isEmpty() )
493 aRet = STR_FROM_ANSI( "Add-In" );
494 return aRet;
497 OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
498 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
500 return getProgrammaticCategoryName( aProgrammaticName );
504 // XCompatibilityNames
506 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
507 const OUString& aProgrammaticName ) throw( uno::RuntimeException )
509 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName );
510 if( !pFData )
511 return uno::Sequence< sheet::LocalizedName >( 0 );
513 const ScaStringList& rStrList = pFData->GetCompNameList();
514 sal_uInt32 nCount = rStrList.Count();
516 uno::Sequence< sheet::LocalizedName > aRet( nCount );
517 sheet::LocalizedName* pArray = aRet.getArray();
519 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
520 pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) );
522 return aRet;
525 namespace {
526 // auxiliary functions
528 sal_Bool IsLeapYear( sal_uInt16 nYear )
530 return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
533 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
535 static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
536 31, 31, 30, 31, 30, 31 };
538 if ( nMonth != 2 )
539 return aDaysInMonth[nMonth-1];
540 else
542 if ( IsLeapYear(nYear) )
543 return aDaysInMonth[nMonth-1] + 1;
544 else
545 return aDaysInMonth[nMonth-1];
550 * Convert a date to a count of days starting from 01/01/0001
552 * The internal representation of a Date used in this Addin
553 * is the number of days between 01/01/0001 and the date
554 * this function converts a Day , Month, Year representation
555 * to this internal Date value.
558 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
560 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
561 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
563 for( sal_uInt16 i = 1; i < nMonth; i++ )
564 nDays += DaysInMonth(i,nYear);
565 nDays += nDay;
567 return nDays;
571 * Convert a count of days starting from 01/01/0001 to a date
573 * The internal representation of a Date used in this Addin
574 * is the number of days between 01/01/0001 and the date
575 * this function converts this internal Date value
576 * to a Day , Month, Year representation of a Date.
579 void DaysToDate( sal_Int32 nDays,
580 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
581 throw( lang::IllegalArgumentException )
583 if( nDays < 0 )
584 throw lang::IllegalArgumentException();
586 sal_Int32 nTempDays;
587 sal_Int32 i = 0;
588 sal_Bool bCalc;
592 nTempDays = nDays;
593 rYear = (sal_uInt16)((nTempDays / 365) - i);
594 nTempDays -= ((sal_Int32) rYear -1) * 365;
595 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
596 bCalc = sal_False;
597 if ( nTempDays < 1 )
599 i++;
600 bCalc = sal_True;
602 else
604 if ( nTempDays > 365 )
606 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
608 i--;
609 bCalc = sal_True;
614 while ( bCalc );
616 rMonth = 1;
617 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
619 nTempDays -= DaysInMonth( rMonth, rYear );
620 rMonth++;
622 rDay = (sal_uInt16)nTempDays;
626 * Get the null date used by the spreadsheet document
628 * The internal representation of a Date used in this Addin
629 * is the number of days between 01/01/0001 and the date
630 * this function returns this internal Date value for the document null date
634 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
635 throw( uno::RuntimeException )
637 if (xOptions.is())
641 uno::Any aAny = xOptions->getPropertyValue(
642 OUString( "NullDate" ) );
643 util::Date aDate;
644 if ( aAny >>= aDate )
645 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
647 catch (uno::Exception&)
652 // no null date available -> no calculations possible
653 throw uno::RuntimeException();
657 // XDateFunctions
660 * Get week difference between 2 dates
662 * new Weeks(date1,date2,mode) function for StarCalc
664 * Two modes of operation are provided.
665 * The first is just a simple division by 7 calculation.
667 * The second calculates the diffence by week of year.
669 * The International Standard IS-8601 has decreed that Monday
670 * shall be the first day of the week.
672 * A week that lies partly in one year and partly in annother
673 * is assigned a number in the year in which most of its days lie.
675 * That means that week 1 of any year is the week that contains the 4. January
677 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
679 * A WeekDay can be then calculated by substracting 1 and calculating the rest of
680 * a division by 7, which gives a 0 - 6 value for Monday - Sunday
682 * Using the 4. January rule explained above the formula
684 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
686 * calculates a number between 0-53 for each day which is in the same year as nJan4
687 * where 0 means that this week belonged to the year before.
689 * If a day in the same or annother year is used in this formula this calculates
690 * an calendar week offset from a given 4. January
692 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
694 * The 4.January of first Date Argument can thus be used to calculate
695 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
697 * which can be optimized to
699 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
701 * Note: All calculations are operating on the long integer data type
702 * % is the modulo operator in C which calculates the rest of an Integer division
705 * mode 0 is the interval between the dates in month, that is days / 7
707 * mode 1 is the difference by week of year
711 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
712 const uno::Reference< beans::XPropertySet >& xOptions,
713 sal_Int32 nStartDate, sal_Int32 nEndDate,
714 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
716 sal_Int32 nNullDate = GetNullDate( xOptions );
718 sal_Int32 nDays1 = nStartDate + nNullDate;
719 sal_Int32 nDays2 = nEndDate + nNullDate;
721 sal_Int32 nRet;
723 if ( nMode == 1 )
725 sal_uInt16 nDay,nMonth,nYear;
726 DaysToDate( nDays1, nDay, nMonth, nYear );
727 sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
729 nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
731 else
733 nRet = (nDays2 - nDays1) / 7;
735 return nRet;
739 * Get month difference between 2 dates
740 * =Month(start, end, mode) Function for StarCalc
742 * two modes are provided
744 * mode 0 is the interval between the dates in month
746 * mode 1 is the difference in calendar month
749 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
750 const uno::Reference< beans::XPropertySet >& xOptions,
751 sal_Int32 nStartDate, sal_Int32 nEndDate,
752 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
754 sal_Int32 nNullDate = GetNullDate( xOptions );
756 sal_Int32 nDays1 = nStartDate + nNullDate;
757 sal_Int32 nDays2 = nEndDate + nNullDate;
759 sal_uInt16 nDay1,nMonth1,nYear1;
760 sal_uInt16 nDay2,nMonth2,nYear2;
761 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
762 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
764 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
765 if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
767 if ( nDays1 < nDays2 )
769 if ( nDay1 > nDay2 )
771 nRet -= 1;
774 else
776 if ( nDay1 < nDay2 )
778 nRet += 1;
782 return nRet;
786 * Get Year difference between 2 dates
788 * two modes are provided
790 * mode 0 is the interval between the dates in years
792 * mode 1 is the difference in calendar years
795 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
796 const uno::Reference< beans::XPropertySet >& xOptions,
797 sal_Int32 nStartDate, sal_Int32 nEndDate,
798 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException )
800 if ( nMode != 1 )
801 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
803 sal_Int32 nNullDate = GetNullDate( xOptions );
805 sal_Int32 nDays1 = nStartDate + nNullDate;
806 sal_Int32 nDays2 = nEndDate + nNullDate;
808 sal_uInt16 nDay1,nMonth1,nYear1;
809 sal_uInt16 nDay2,nMonth2,nYear2;
810 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
811 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
813 return nYear2 - nYear1;
817 * Check if a Date is in a leap year in the Gregorian calendar
820 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
821 const uno::Reference< beans::XPropertySet >& xOptions,
822 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
824 sal_Int32 nNullDate = GetNullDate( xOptions );
825 sal_Int32 nDays = nDate + nNullDate;
827 sal_uInt16 nDay, nMonth, nYear;
828 DaysToDate(nDays,nDay,nMonth,nYear);
830 return (sal_Int32)IsLeapYear(nYear);
834 * Get the Number of Days in the month for a date
837 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
838 const uno::Reference<beans::XPropertySet>& xOptions,
839 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
841 sal_Int32 nNullDate = GetNullDate( xOptions );
842 sal_Int32 nDays = nDate + nNullDate;
844 sal_uInt16 nDay, nMonth, nYear;
845 DaysToDate(nDays,nDay,nMonth,nYear);
847 return DaysInMonth( nMonth, nYear );
851 * Get number of days in the year of a date specified
854 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
855 const uno::Reference< beans::XPropertySet >& xOptions,
856 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
858 sal_Int32 nNullDate = GetNullDate( xOptions );
859 sal_Int32 nDays = nDate + nNullDate;
861 sal_uInt16 nDay, nMonth, nYear;
862 DaysToDate(nDays,nDay,nMonth,nYear);
864 return ( IsLeapYear(nYear) ? 366 : 365 );
868 * Get number of weeks in the year for a date
870 * Most years have 52 weeks, but years that start on a Thursday
871 * and leep years that start on a Wednesday have 53 weeks
873 * The International Standard IS-8601 has decreed that Monday
874 * shall be the first day of the week.
876 * A WeekDay can be calculated by substracting 1 and calculating the rest of
877 * a division by 7 from the internal date represention
878 * which gives a 0 - 6 value for Monday - Sunday
880 * @see #IsLeapYear #WeekNumber
883 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
884 const uno::Reference< beans::XPropertySet >& xOptions,
885 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException )
887 sal_Int32 nNullDate = GetNullDate( xOptions );
888 sal_Int32 nDays = nDate + nNullDate;
890 sal_uInt16 nDay, nMonth, nYear;
891 DaysToDate(nDays,nDay,nMonth,nYear);
893 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
895 sal_Int32 nRet;
896 if ( nJan1WeekDay == 3 ) /* Thursday */
897 nRet = 53;
898 else if ( nJan1WeekDay == 2 ) /* Wednesday */
899 nRet = ( IsLeapYear(nYear) ? 53 : 52 );
900 else
901 nRet = 52;
903 return nRet;
907 * Encrypt or decrypt a string using ROT13 algorithm
909 * This function rotates each character by 13 in the alphabet.
910 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
913 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) throw( uno::RuntimeException, lang::IllegalArgumentException )
915 OUStringBuffer aBuffer( aSrcString );
916 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
918 sal_Unicode cChar = aBuffer[nIndex];
919 if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) ||
920 ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) )
921 cChar -= 26;
922 aBuffer[nIndex] = cChar;
924 return aBuffer.makeStringAndClear();
927 //------------------------------------------------------------------
929 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */