1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 //------------------------------------------------------------------ 29 // 30 // date functions add in 31 // 32 //------------------------------------------------------------------ 33 34 #include "datefunc.hxx" 35 #ifndef _SCA_DATEFUNC_HRC 36 #include "datefunc.hrc" 37 #endif 38 #include <cppuhelper/factory.hxx> 39 #include <osl/diagnose.h> 40 #include <rtl/ustrbuf.hxx> 41 #include <tools/resmgr.hxx> 42 #include <tools/rcid.h> 43 #include <com/sun/star/util/Date.hpp> 44 45 using namespace ::com::sun::star; 46 using namespace ::rtl; 47 48 //------------------------------------------------------------------ 49 50 #define ADDIN_SERVICE "com.sun.star.sheet.AddIn" 51 #define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions" 52 #define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl" 53 54 //------------------------------------------------------------------ 55 56 #define STR_FROM_ANSI( s ) OUString( s, strlen( s ), RTL_TEXTENCODING_MS_1252 ) 57 58 //------------------------------------------------------------------ 59 60 const sal_uInt32 ScaList::nStartSize = 16; 61 const sal_uInt32 ScaList::nIncrSize = 16; 62 63 ScaList::ScaList() : 64 pData( new void*[ nStartSize ] ), 65 nSize( nStartSize ), 66 nCount( 0 ), 67 nCurr( 0 ) 68 { 69 } 70 71 ScaList::~ScaList() 72 { 73 delete[] pData; 74 } 75 76 void ScaList::_Grow() 77 { 78 nSize += nIncrSize; 79 80 void** pNewData = new void*[ nSize ]; 81 memcpy( pNewData, pData, nCount * sizeof( void* ) ); 82 83 delete[] pData; 84 pData = pNewData; 85 } 86 87 void ScaList::Insert( void* pNew, sal_uInt32 nIndex ) 88 { 89 if( nIndex >= nCount ) 90 Append( pNew ); 91 else 92 { 93 Grow(); 94 95 void** pIns = pData + nIndex; 96 memmove( pIns + 1, pIns, (nCount - nIndex) * sizeof( void* ) ); 97 98 *pIns = pNew; 99 nCount++; 100 } 101 } 102 103 104 //------------------------------------------------------------------ 105 106 ScaStringList::~ScaStringList() 107 { 108 for( OUString* pStr = First(); pStr; pStr = Next() ) 109 delete pStr; 110 } 111 112 //------------------------------------------------------------------ 113 114 ScaResId::ScaResId( sal_uInt16 nId, ResMgr& rResMgr ) : 115 ResId( nId, rResMgr ) 116 { 117 } 118 119 120 //------------------------------------------------------------------ 121 122 #define UNIQUE sal_False // function name does not exist in Calc 123 #define DOUBLE sal_True // function name exists in Calc 124 125 #define STDPAR sal_False // all parameters are described 126 #define INTPAR sal_True // first parameter is internal 127 128 #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \ 129 { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar } 130 131 const ScaFuncDataBase pFuncDataArr[] = 132 { 133 FUNCDATA( DiffWeeks, 3, ScaCat_DateTime, UNIQUE, INTPAR ), 134 FUNCDATA( DiffMonths, 3, ScaCat_DateTime, UNIQUE, INTPAR ), 135 FUNCDATA( DiffYears, 3, ScaCat_DateTime, UNIQUE, INTPAR ), 136 FUNCDATA( IsLeapYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ), 137 FUNCDATA( DaysInMonth, 1, ScaCat_DateTime, UNIQUE, INTPAR ), 138 FUNCDATA( DaysInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ), 139 FUNCDATA( WeeksInYear, 1, ScaCat_DateTime, UNIQUE, INTPAR ), 140 FUNCDATA( Rot13, 1, ScaCat_Text, UNIQUE, STDPAR ) 141 }; 142 143 #undef FUNCDATA 144 145 146 //------------------------------------------------------------------ 147 148 ScaFuncData::ScaFuncData( const ScaFuncDataBase& rBaseData, ResMgr& rResMgr ) : 149 aIntName( OUString::createFromAscii( rBaseData.pIntName ) ), 150 nUINameID( rBaseData.nUINameID ), 151 nDescrID( rBaseData.nDescrID ), 152 nCompListID( rBaseData.nCompListID ), 153 nParamCount( rBaseData.nParamCount ), 154 eCat( rBaseData.eCat ), 155 bDouble( rBaseData.bDouble ), 156 bWithOpt( rBaseData.bWithOpt ) 157 { 158 ScaResStringArrLoader aArrLoader( RID_DATE_DEFFUNCTION_NAMES, nCompListID, rResMgr ); 159 const ResStringArray& rArr = aArrLoader.GetStringArray(); 160 161 for( sal_uInt16 nIndex = 0; nIndex < rArr.Count(); nIndex++ ) 162 aCompList.Append( rArr.GetString( nIndex ) ); 163 } 164 165 ScaFuncData::~ScaFuncData() 166 { 167 } 168 169 sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const 170 { 171 if( !bWithOpt ) 172 nParam++; 173 return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2); 174 } 175 176 177 //------------------------------------------------------------------ 178 179 ScaFuncDataList::ScaFuncDataList( ResMgr& rResMgr ) : 180 nLast( 0xFFFFFFFF ) 181 { 182 const sal_uInt32 nCnt = sizeof( pFuncDataArr ) / sizeof( ScaFuncDataBase ); 183 184 for( sal_uInt16 nIndex = 0; nIndex < nCnt; nIndex++ ) 185 Append( new ScaFuncData( pFuncDataArr[ nIndex ], rResMgr ) ); 186 } 187 188 ScaFuncDataList::~ScaFuncDataList() 189 { 190 for( ScaFuncData* pFData = First(); pFData; pFData = Next() ) 191 delete pFData; 192 } 193 194 const ScaFuncData* ScaFuncDataList::Get( const OUString& rProgrammaticName ) const 195 { 196 if( aLastName == rProgrammaticName ) 197 return Get( nLast ); 198 199 for( sal_uInt32 nIndex = 0; nIndex < Count(); nIndex++ ) 200 { 201 const ScaFuncData* pCurr = Get( nIndex ); 202 if( pCurr->Is( rProgrammaticName ) ) 203 { 204 const_cast< ScaFuncDataList* >( this )->aLastName = rProgrammaticName; 205 const_cast< ScaFuncDataList* >( this )->nLast = nIndex; 206 return pCurr; 207 } 208 } 209 return NULL; 210 } 211 212 213 //------------------------------------------------------------------ 214 215 ScaFuncRes::ScaFuncRes( ResId& rResId, ResMgr& rResMgr, sal_uInt16 nIndex, OUString& rRet ) : 216 Resource( rResId ) 217 { 218 rRet = String( ScaResId( nIndex, rResMgr ) ); 219 FreeResource(); 220 } 221 222 223 //------------------------------------------------------------------ 224 // 225 // entry points for service registration / instantiation 226 // 227 //------------------------------------------------------------------ 228 229 uno::Reference< uno::XInterface > SAL_CALL ScaDateAddIn_CreateInstance( 230 const uno::Reference< lang::XMultiServiceFactory >& ) 231 { 232 static uno::Reference< uno::XInterface > xInst = (cppu::OWeakObject*) new ScaDateAddIn(); 233 return xInst; 234 } 235 236 237 //------------------------------------------------------------------------ 238 239 extern "C" { 240 241 void SAL_CALL component_getImplementationEnvironment( 242 const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) 243 { 244 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 245 } 246 247 void * SAL_CALL component_getFactory( 248 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) 249 { 250 void* pRet = 0; 251 252 if ( pServiceManager && 253 OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() ) 254 { 255 uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory( 256 reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ), 257 ScaDateAddIn::getImplementationName_Static(), 258 ScaDateAddIn_CreateInstance, 259 ScaDateAddIn::getSupportedServiceNames_Static() ) ); 260 261 if (xFactory.is()) 262 { 263 xFactory->acquire(); 264 pRet = xFactory.get(); 265 } 266 } 267 268 return pRet; 269 } 270 271 } // extern C 272 273 //------------------------------------------------------------------------ 274 // 275 // "normal" service implementation 276 // 277 //------------------------------------------------------------------------ 278 279 ScaDateAddIn::ScaDateAddIn() : 280 pDefLocales( NULL ), 281 pResMgr( NULL ), 282 pFuncDataList( NULL ) 283 { 284 } 285 286 ScaDateAddIn::~ScaDateAddIn() 287 { 288 if( pFuncDataList ) 289 delete pFuncDataList; 290 if( pDefLocales ) 291 delete[] pDefLocales; 292 293 // pResMgr already deleted (_all_ resource managers are deleted _before_ this dtor is called) 294 } 295 296 static const sal_Char* pLang[] = { "de", "en" }; 297 static const sal_Char* pCoun[] = { "DE", "US" }; 298 static const sal_uInt32 nNumOfLoc = sizeof( pLang ) / sizeof( sal_Char* ); 299 300 void ScaDateAddIn::InitDefLocales() 301 { 302 pDefLocales = new lang::Locale[ nNumOfLoc ]; 303 304 for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ ) 305 { 306 pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] ); 307 pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] ); 308 } 309 } 310 311 const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex ) 312 { 313 if( !pDefLocales ) 314 InitDefLocales(); 315 316 return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc; 317 } 318 319 ResMgr& ScaDateAddIn::GetResMgr() throw( uno::RuntimeException ) 320 { 321 if( !pResMgr ) 322 { 323 InitData(); // try to get resource manager 324 if( !pResMgr ) 325 throw uno::RuntimeException(); 326 } 327 return *pResMgr; 328 } 329 330 void ScaDateAddIn::InitData() 331 { 332 if( pResMgr ) 333 delete pResMgr; 334 335 OString aModName( "date" ); 336 pResMgr = ResMgr::CreateResMgr( (const sal_Char*) aModName, 337 aFuncLoc ); 338 339 if( pFuncDataList ) 340 delete pFuncDataList; 341 342 pFuncDataList = pResMgr ? new ScaFuncDataList( *pResMgr ) : NULL; 343 344 if( pDefLocales ) 345 { 346 delete pDefLocales; 347 pDefLocales = NULL; 348 } 349 } 350 351 OUString ScaDateAddIn::GetDisplFuncStr( sal_uInt16 nResId ) throw( uno::RuntimeException ) 352 { 353 return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString(); 354 } 355 356 OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) throw( uno::RuntimeException ) 357 { 358 OUString aRet; 359 360 ScaResPublisher aResPubl( ScaResId( RID_DATE_FUNCTION_DESCRIPTIONS, GetResMgr() ) ); 361 ScaResId aResId( nResId, GetResMgr() ); 362 aResId.SetRT( RSC_RESOURCE ); 363 364 if( aResPubl.IsAvailableRes( aResId ) ) 365 ScaFuncRes aSubRes( aResId, GetResMgr(), nStrIndex, aRet ); 366 367 aResPubl.FreeResource(); 368 return aRet; 369 } 370 371 372 //------------------------------------------------------------------------ 373 374 OUString ScaDateAddIn::getImplementationName_Static() 375 { 376 return OUString::createFromAscii( MY_IMPLNAME ); 377 } 378 379 uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static() 380 { 381 uno::Sequence< OUString > aRet( 2 ); 382 OUString* pArray = aRet.getArray(); 383 pArray[0] = OUString::createFromAscii( ADDIN_SERVICE ); 384 pArray[1] = OUString::createFromAscii( MY_SERVICE ); 385 return aRet; 386 } 387 388 // XServiceName 389 390 OUString SAL_CALL ScaDateAddIn::getServiceName() throw( uno::RuntimeException ) 391 { 392 // name of specific AddIn service 393 return OUString::createFromAscii( MY_SERVICE ); 394 } 395 396 // XServiceInfo 397 398 OUString SAL_CALL ScaDateAddIn::getImplementationName() throw( uno::RuntimeException ) 399 { 400 return getImplementationName_Static(); 401 } 402 403 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) throw( uno::RuntimeException ) 404 { 405 return aServiceName.equalsAscii( ADDIN_SERVICE ) || 406 aServiceName.equalsAscii( MY_SERVICE ); 407 } 408 409 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() throw( uno::RuntimeException ) 410 { 411 return getSupportedServiceNames_Static(); 412 } 413 414 // XLocalizable 415 416 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) throw( uno::RuntimeException ) 417 { 418 aFuncLoc = eLocale; 419 InitData(); // change of locale invalidates resources! 420 } 421 422 lang::Locale SAL_CALL ScaDateAddIn::getLocale() throw( uno::RuntimeException ) 423 { 424 return aFuncLoc; 425 } 426 427 //------------------------------------------------------------------ 428 // 429 // function descriptions start here 430 // 431 //------------------------------------------------------------------ 432 433 // XAddIn 434 435 OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& ) throw( uno::RuntimeException ) 436 { 437 // not used by calc 438 // (but should be implemented for other uses of the AddIn service) 439 return OUString(); 440 } 441 442 OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) 443 { 444 OUString aRet; 445 446 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 447 if( pFData ) 448 { 449 aRet = GetDisplFuncStr( pFData->GetUINameID() ); 450 if( pFData->IsDouble() ) 451 aRet += STR_FROM_ANSI( "_ADD" ); 452 } 453 else 454 { 455 aRet = STR_FROM_ANSI( "UNKNOWNFUNC_" ); 456 aRet += aProgrammaticName; 457 } 458 459 return aRet; 460 } 461 462 OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) 463 { 464 OUString aRet; 465 466 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 467 if( pFData ) 468 aRet = GetFuncDescrStr( pFData->GetDescrID(), 1 ); 469 470 return aRet; 471 } 472 473 OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName( 474 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) 475 { 476 OUString aRet; 477 478 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 479 if( pFData && (nArgument <= 0xFFFF) ) 480 { 481 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); 482 if( nStr ) 483 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr ); 484 else 485 aRet = STR_FROM_ANSI( "internal" ); 486 } 487 488 return aRet; 489 } 490 491 OUString SAL_CALL ScaDateAddIn::getArgumentDescription( 492 const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) 493 { 494 OUString aRet; 495 496 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 497 if( pFData && (nArgument <= 0xFFFF) ) 498 { 499 sal_uInt16 nStr = pFData->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) ); 500 if( nStr ) 501 aRet = GetFuncDescrStr( pFData->GetDescrID(), nStr + 1 ); 502 else 503 aRet = STR_FROM_ANSI( "for internal use only" ); 504 } 505 506 return aRet; 507 } 508 509 OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName( 510 const OUString& aProgrammaticName ) throw( uno::RuntimeException ) 511 { 512 OUString aRet; 513 514 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 515 if( pFData ) 516 { 517 switch( pFData->GetCategory() ) 518 { 519 case ScaCat_DateTime: aRet = STR_FROM_ANSI( "Date&Time" ); break; 520 case ScaCat_Text: aRet = STR_FROM_ANSI( "Text" ); break; 521 case ScaCat_Finance: aRet = STR_FROM_ANSI( "Financial" ); break; 522 case ScaCat_Inf: aRet = STR_FROM_ANSI( "Information" ); break; 523 case ScaCat_Math: aRet = STR_FROM_ANSI( "Mathematical" ); break; 524 case ScaCat_Tech: aRet = STR_FROM_ANSI( "Technical" ); break; 525 default: // to prevent compiler warnings 526 break; 527 } 528 } 529 530 if( !aRet.getLength() ) 531 aRet = STR_FROM_ANSI( "Add-In" ); 532 return aRet; 533 } 534 535 OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName( 536 const OUString& aProgrammaticName ) throw( uno::RuntimeException ) 537 { 538 return getProgrammaticCategoryName( aProgrammaticName ); 539 } 540 541 542 // XCompatibilityNames 543 544 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames( 545 const OUString& aProgrammaticName ) throw( uno::RuntimeException ) 546 { 547 const ScaFuncData* pFData = pFuncDataList->Get( aProgrammaticName ); 548 if( !pFData ) 549 return uno::Sequence< sheet::LocalizedName >( 0 ); 550 551 const ScaStringList& rStrList = pFData->GetCompNameList(); 552 sal_uInt32 nCount = rStrList.Count(); 553 554 uno::Sequence< sheet::LocalizedName > aRet( nCount ); 555 sheet::LocalizedName* pArray = aRet.getArray(); 556 557 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ ) 558 pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), *rStrList.Get( nIndex ) ); 559 560 return aRet; 561 } 562 563 564 //------------------------------------------------------------------ 565 // 566 // function implementation starts here 567 // 568 //------------------------------------------------------------------ 569 570 // auxiliary functions 571 572 sal_Bool IsLeapYear( sal_uInt16 nYear ) 573 { 574 return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0)); 575 } 576 577 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear ) 578 { 579 static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, 580 31, 31, 30, 31, 30, 31 }; 581 582 if ( nMonth != 2 ) 583 return aDaysInMonth[nMonth-1]; 584 else 585 { 586 if ( IsLeapYear(nYear) ) 587 return aDaysInMonth[nMonth-1] + 1; 588 else 589 return aDaysInMonth[nMonth-1]; 590 } 591 } 592 593 /** 594 * Convert a date to a count of days starting from 01/01/0001 595 * 596 * The internal representation of a Date used in this Addin 597 * is the number of days between 01/01/0001 and the date 598 * this function converts a Day , Month, Year representation 599 * to this internal Date value. 600 */ 601 602 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear ) 603 { 604 sal_Int32 nDays = ((sal_Int32)nYear-1) * 365; 605 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400); 606 607 for( sal_uInt16 i = 1; i < nMonth; i++ ) 608 nDays += DaysInMonth(i,nYear); 609 nDays += nDay; 610 611 return nDays; 612 } 613 614 /** 615 * Convert a count of days starting from 01/01/0001 to a date 616 * 617 * The internal representation of a Date used in this Addin 618 * is the number of days between 01/01/0001 and the date 619 * this function converts this internal Date value 620 * to a Day , Month, Year representation of a Date. 621 */ 622 623 void DaysToDate( sal_Int32 nDays, 624 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear ) 625 throw( lang::IllegalArgumentException ) 626 { 627 if( nDays < 0 ) 628 throw lang::IllegalArgumentException(); 629 630 sal_Int32 nTempDays; 631 sal_Int32 i = 0; 632 sal_Bool bCalc; 633 634 do 635 { 636 nTempDays = nDays; 637 rYear = (sal_uInt16)((nTempDays / 365) - i); 638 nTempDays -= ((sal_Int32) rYear -1) * 365; 639 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400); 640 bCalc = sal_False; 641 if ( nTempDays < 1 ) 642 { 643 i++; 644 bCalc = sal_True; 645 } 646 else 647 { 648 if ( nTempDays > 365 ) 649 { 650 if ( (nTempDays != 366) || !IsLeapYear( rYear ) ) 651 { 652 i--; 653 bCalc = sal_True; 654 } 655 } 656 } 657 } 658 while ( bCalc ); 659 660 rMonth = 1; 661 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) ) 662 { 663 nTempDays -= DaysInMonth( rMonth, rYear ); 664 rMonth++; 665 } 666 rDay = (sal_uInt16)nTempDays; 667 } 668 669 /** 670 * Get the null date used by the spreadsheet document 671 * 672 * The internal representation of a Date used in this Addin 673 * is the number of days between 01/01/0001 and the date 674 * this function returns this internal Date value for the document null date 675 * 676 */ 677 678 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions ) 679 throw( uno::RuntimeException ) 680 { 681 if (xOptions.is()) 682 { 683 try 684 { 685 uno::Any aAny = xOptions->getPropertyValue( 686 OUString::createFromAscii( "NullDate" ) ); 687 util::Date aDate; 688 if ( aAny >>= aDate ) 689 return DateToDays( aDate.Day, aDate.Month, aDate.Year ); 690 } 691 catch (uno::Exception&) 692 { 693 } 694 } 695 696 // no null date available -> no calculations possible 697 throw uno::RuntimeException(); 698 } 699 700 // XDateFunctions 701 702 /** 703 * Get week difference between 2 dates 704 * 705 * new Weeks(date1,date2,mode) function for StarCalc 706 * 707 * Two modes of operation are provided. 708 * The first is just a simple division by 7 calculation. 709 * 710 * The second calculates the diffence by week of year. 711 * 712 * The International Standard IS-8601 has decreed that Monday 713 * shall be the first day of the week. 714 * 715 * A week that lies partly in one year and partly in annother 716 * is assigned a number in the the year in which most of its days lie. 717 * 718 * That means that week 1 of any year is the week that contains the 4. January 719 * 720 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001 721 * 722 * A WeekDay can be then calculated by substracting 1 and calculating the rest of 723 * a division by 7, which gives a 0 - 6 value for Monday - Sunday 724 * 725 * Using the 4. January rule explained above the formula 726 * 727 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; 728 * 729 * calculates a number between 0-53 for each day which is in the same year as nJan4 730 * where 0 means that this week belonged to the year before. 731 * 732 * If a day in the same or annother year is used in this formula this calculates 733 * an calendar week offset from a given 4. January 734 * 735 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; 736 * 737 * The 4.January of first Date Argument can thus be used to calculate 738 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1 739 * 740 * which can be optimized to 741 * 742 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) 743 * 744 * Note: All calculations are operating on the long integer data type 745 * % is the modulo operator in C which calculates the rest of an Integer division 746 * 747 * 748 * mode 0 is the interval between the dates in month, that is days / 7 749 * 750 * mode 1 is the difference by week of year 751 * 752 */ 753 754 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks( 755 const uno::Reference< beans::XPropertySet >& xOptions, 756 sal_Int32 nStartDate, sal_Int32 nEndDate, 757 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 758 { 759 sal_Int32 nNullDate = GetNullDate( xOptions ); 760 761 sal_Int32 nDays1 = nStartDate + nNullDate; 762 sal_Int32 nDays2 = nEndDate + nNullDate; 763 764 sal_Int32 nRet; 765 766 if ( nMode == 1 ) 767 { 768 sal_uInt16 nDay,nMonth,nYear; 769 DaysToDate( nDays1, nDay, nMonth, nYear ); 770 sal_Int32 nJan4 = DateToDays( 4, 1, nYear ); 771 772 nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ); 773 } 774 else 775 { 776 nRet = (nDays2 - nDays1) / 7; 777 } 778 return nRet; 779 } 780 781 /** 782 * Get month difference between 2 dates 783 * =Month(start, end, mode) Function for StarCalc 784 * 785 * two modes are provided 786 * 787 * mode 0 is the interval between the dates in month 788 * 789 * mode 1 is the difference in calendar month 790 */ 791 792 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths( 793 const uno::Reference< beans::XPropertySet >& xOptions, 794 sal_Int32 nStartDate, sal_Int32 nEndDate, 795 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 796 { 797 sal_Int32 nNullDate = GetNullDate( xOptions ); 798 799 sal_Int32 nDays1 = nStartDate + nNullDate; 800 sal_Int32 nDays2 = nEndDate + nNullDate; 801 802 sal_uInt16 nDay1,nMonth1,nYear1; 803 sal_uInt16 nDay2,nMonth2,nYear2; 804 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 805 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 806 807 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12; 808 if ( nMode == 1 || nDays1 == nDays2 ) return nRet; 809 810 if ( nDays1 < nDays2 ) 811 { 812 if ( nDay1 > nDay2 ) 813 { 814 nRet -= 1; 815 } 816 } 817 else 818 { 819 if ( nDay1 < nDay2 ) 820 { 821 nRet += 1; 822 } 823 } 824 825 return nRet; 826 } 827 828 /** 829 * Get Year difference between 2 dates 830 * 831 * two modes are provided 832 * 833 * mode 0 is the interval between the dates in years 834 * 835 * mode 1 is the difference in calendar years 836 */ 837 838 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears( 839 const uno::Reference< beans::XPropertySet >& xOptions, 840 sal_Int32 nStartDate, sal_Int32 nEndDate, 841 sal_Int32 nMode ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 842 { 843 if ( nMode != 1 ) 844 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12; 845 846 sal_Int32 nNullDate = GetNullDate( xOptions ); 847 848 sal_Int32 nDays1 = nStartDate + nNullDate; 849 sal_Int32 nDays2 = nEndDate + nNullDate; 850 851 sal_uInt16 nDay1,nMonth1,nYear1; 852 sal_uInt16 nDay2,nMonth2,nYear2; 853 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 854 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 855 856 return nYear2 - nYear1; 857 } 858 859 /** 860 * Check if a Date is in a leap year in the Gregorian calendar 861 */ 862 863 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear( 864 const uno::Reference< beans::XPropertySet >& xOptions, 865 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 866 { 867 sal_Int32 nNullDate = GetNullDate( xOptions ); 868 sal_Int32 nDays = nDate + nNullDate; 869 870 sal_uInt16 nDay, nMonth, nYear; 871 DaysToDate(nDays,nDay,nMonth,nYear); 872 873 return (sal_Int32)IsLeapYear(nYear); 874 } 875 876 /** 877 * Get the Number of Days in the month for a date 878 */ 879 880 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth( 881 const uno::Reference<beans::XPropertySet>& xOptions, 882 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 883 { 884 sal_Int32 nNullDate = GetNullDate( xOptions ); 885 sal_Int32 nDays = nDate + nNullDate; 886 887 sal_uInt16 nDay, nMonth, nYear; 888 DaysToDate(nDays,nDay,nMonth,nYear); 889 890 return DaysInMonth( nMonth, nYear ); 891 } 892 893 /** 894 * Get number of days in the year of a date specified 895 */ 896 897 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear( 898 const uno::Reference< beans::XPropertySet >& xOptions, 899 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 900 { 901 sal_Int32 nNullDate = GetNullDate( xOptions ); 902 sal_Int32 nDays = nDate + nNullDate; 903 904 sal_uInt16 nDay, nMonth, nYear; 905 DaysToDate(nDays,nDay,nMonth,nYear); 906 907 return ( IsLeapYear(nYear) ? 366 : 365 ); 908 } 909 910 /** 911 * Get number of weeks in the year for a date 912 * 913 * Most years have 52 weeks, but years that start on a Thursday 914 * and leep years that start on a Wednesday have 53 weeks 915 * 916 * The International Standard IS-8601 has decreed that Monday 917 * shall be the first day of the week. 918 * 919 * A WeekDay can be calculated by substracting 1 and calculating the rest of 920 * a division by 7 from the internal date represention 921 * which gives a 0 - 6 value for Monday - Sunday 922 * 923 * @see #IsLeapYear #WeekNumber 924 */ 925 926 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear( 927 const uno::Reference< beans::XPropertySet >& xOptions, 928 sal_Int32 nDate ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 929 { 930 sal_Int32 nNullDate = GetNullDate( xOptions ); 931 sal_Int32 nDays = nDate + nNullDate; 932 933 sal_uInt16 nDay, nMonth, nYear; 934 DaysToDate(nDays,nDay,nMonth,nYear); 935 936 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7; 937 938 sal_Int32 nRet; 939 if ( nJan1WeekDay == 3 ) /* Thursday */ 940 nRet = 53; 941 else if ( nJan1WeekDay == 2 ) /* Wednesday */ 942 nRet = ( IsLeapYear(nYear) ? 53 : 52 ); 943 else 944 nRet = 52; 945 946 return nRet; 947 } 948 949 /** 950 * Encrypt or decrypt a string using ROT13 algorithm 951 * 952 * This function rotates each character by 13 in the alphabet. 953 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified. 954 */ 955 956 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) throw( uno::RuntimeException, lang::IllegalArgumentException ) 957 { 958 OUStringBuffer aBuffer( aSrcString ); 959 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ ) 960 { 961 sal_Unicode cChar = aBuffer.charAt( nIndex ); 962 if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) || 963 ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) ) 964 cChar -= 26; 965 aBuffer.setCharAt( nIndex, cChar ); 966 } 967 return aBuffer.makeStringAndClear(); 968 } 969 970 //------------------------------------------------------------------ 971 972