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