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() 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 ) 347 { 348 return ScaResStringLoader( RID_DATE_FUNCTION_NAMES, nResId, GetResMgr() ).GetString(); 349 } 350 351 OUString ScaDateAddIn::GetFuncDescrStr( sal_uInt16 nResId, sal_uInt16 nStrIndex ) 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() 386 { 387 // name of specific AddIn service 388 return OUString::createFromAscii( MY_SERVICE ); 389 } 390 391 // XServiceInfo 392 393 OUString SAL_CALL ScaDateAddIn::getImplementationName() 394 { 395 return getImplementationName_Static(); 396 } 397 398 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName ) 399 { 400 return aServiceName.equalsAscii( ADDIN_SERVICE ) || 401 aServiceName.equalsAscii( MY_SERVICE ); 402 } 403 404 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames() 405 { 406 return getSupportedServiceNames_Static(); 407 } 408 409 // XLocalizable 410 411 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale ) 412 { 413 aFuncLoc = eLocale; 414 InitData(); // change of locale invalidates resources! 415 } 416 417 lang::Locale SAL_CALL ScaDateAddIn::getLocale() 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& ) 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 ) 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 ) 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 ) 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 ) 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 ) 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 ) 532 { 533 return getProgrammaticCategoryName( aProgrammaticName ); 534 } 535 536 537 // XCompatibilityNames 538 539 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames( 540 const OUString& aProgrammaticName ) 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 { 621 if( nDays < 0 ) 622 throw lang::IllegalArgumentException(); 623 624 sal_Int32 nTempDays; 625 sal_Int32 i = 0; 626 sal_Bool bCalc; 627 628 do 629 { 630 nTempDays = nDays; 631 rYear = (sal_uInt16)((nTempDays / 365) - i); 632 nTempDays -= ((sal_Int32) rYear -1) * 365; 633 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400); 634 bCalc = sal_False; 635 if ( nTempDays < 1 ) 636 { 637 i++; 638 bCalc = sal_True; 639 } 640 else 641 { 642 if ( nTempDays > 365 ) 643 { 644 if ( (nTempDays != 366) || !IsLeapYear( rYear ) ) 645 { 646 i--; 647 bCalc = sal_True; 648 } 649 } 650 } 651 } 652 while ( bCalc ); 653 654 rMonth = 1; 655 while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) ) 656 { 657 nTempDays -= DaysInMonth( rMonth, rYear ); 658 rMonth++; 659 } 660 rDay = (sal_uInt16)nTempDays; 661 } 662 663 /** 664 * Get the null date used by the spreadsheet document 665 * 666 * The internal representation of a Date used in this Addin 667 * is the number of days between 01/01/0001 and the date 668 * this function returns this internal Date value for the document null date 669 * 670 */ 671 672 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions ) 673 { 674 if (xOptions.is()) 675 { 676 try 677 { 678 uno::Any aAny = xOptions->getPropertyValue( 679 OUString::createFromAscii( "NullDate" ) ); 680 util::Date aDate; 681 if ( aAny >>= aDate ) 682 return DateToDays( aDate.Day, aDate.Month, aDate.Year ); 683 } 684 catch (uno::Exception&) 685 { 686 } 687 } 688 689 // no null date available -> no calculations possible 690 throw uno::RuntimeException(); 691 } 692 693 // XDateFunctions 694 695 /** 696 * Get week difference between 2 dates 697 * 698 * new Weeks(date1,date2,mode) function for StarCalc 699 * 700 * Two modes of operation are provided. 701 * The first is just a simple division by 7 calculation. 702 * 703 * The second calculates the difference by week of year. 704 * 705 * The International Standard IS-8601 has decreed that Monday 706 * shall be the first day of the week. 707 * 708 * A week that lies partly in one year and partly in another 709 * is assigned a number in the year in which most of its days lie. 710 * 711 * That means that week 1 of any year is the week that contains the 4. January 712 * 713 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001 714 * 715 * A WeekDay can be then calculated by subtracting 1 and calculating the rest of 716 * a division by 7, which gives a 0 - 6 value for Monday - Sunday 717 * 718 * Using the 4. January rule explained above the formula 719 * 720 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; 721 * 722 * calculates a number between 0-53 for each day which is in the same year as nJan4 723 * where 0 means that this week belonged to the year before. 724 * 725 * If a day in the same or another year is used in this formula this calculates 726 * an calendar week offset from a given 4. January 727 * 728 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1; 729 * 730 * The 4.January of first Date Argument can thus be used to calculate 731 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1 732 * 733 * which can be optimized to 734 * 735 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) 736 * 737 * Note: All calculations are operating on the long integer data type 738 * % is the modulo operator in C which calculates the rest of an Integer division 739 * 740 * 741 * mode 0 is the interval between the dates in month, that is days / 7 742 * 743 * mode 1 is the difference by week of year 744 * 745 */ 746 747 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks( 748 const uno::Reference< beans::XPropertySet >& xOptions, 749 sal_Int32 nStartDate, sal_Int32 nEndDate, 750 sal_Int32 nMode ) 751 { 752 sal_Int32 nNullDate = GetNullDate( xOptions ); 753 754 sal_Int32 nDays1 = nStartDate + nNullDate; 755 sal_Int32 nDays2 = nEndDate + nNullDate; 756 757 sal_Int32 nRet; 758 759 if ( nMode == 1 ) 760 { 761 sal_uInt16 nDay,nMonth,nYear; 762 DaysToDate( nDays1, nDay, nMonth, nYear ); 763 sal_Int32 nJan4 = DateToDays( 4, 1, nYear ); 764 765 nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ); 766 } 767 else 768 { 769 nRet = (nDays2 - nDays1) / 7; 770 } 771 return nRet; 772 } 773 774 /** 775 * Get month difference between 2 dates 776 * =Month(start, end, mode) Function for StarCalc 777 * 778 * two modes are provided 779 * 780 * mode 0 is the interval between the dates in month 781 * 782 * mode 1 is the difference in calendar month 783 */ 784 785 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths( 786 const uno::Reference< beans::XPropertySet >& xOptions, 787 sal_Int32 nStartDate, sal_Int32 nEndDate, 788 sal_Int32 nMode ) 789 { 790 sal_Int32 nNullDate = GetNullDate( xOptions ); 791 792 sal_Int32 nDays1 = nStartDate + nNullDate; 793 sal_Int32 nDays2 = nEndDate + nNullDate; 794 795 sal_uInt16 nDay1,nMonth1,nYear1; 796 sal_uInt16 nDay2,nMonth2,nYear2; 797 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 798 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 799 800 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12; 801 if ( nMode == 1 || nDays1 == nDays2 ) return nRet; 802 803 if ( nDays1 < nDays2 ) 804 { 805 if ( nDay1 > nDay2 ) 806 { 807 nRet -= 1; 808 } 809 } 810 else 811 { 812 if ( nDay1 < nDay2 ) 813 { 814 nRet += 1; 815 } 816 } 817 818 return nRet; 819 } 820 821 /** 822 * Get Year difference between 2 dates 823 * 824 * two modes are provided 825 * 826 * mode 0 is the interval between the dates in years 827 * 828 * mode 1 is the difference in calendar years 829 */ 830 831 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears( 832 const uno::Reference< beans::XPropertySet >& xOptions, 833 sal_Int32 nStartDate, sal_Int32 nEndDate, 834 sal_Int32 nMode ) 835 { 836 if ( nMode != 1 ) 837 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12; 838 839 sal_Int32 nNullDate = GetNullDate( xOptions ); 840 841 sal_Int32 nDays1 = nStartDate + nNullDate; 842 sal_Int32 nDays2 = nEndDate + nNullDate; 843 844 sal_uInt16 nDay1,nMonth1,nYear1; 845 sal_uInt16 nDay2,nMonth2,nYear2; 846 DaysToDate(nDays1,nDay1,nMonth1,nYear1); 847 DaysToDate(nDays2,nDay2,nMonth2,nYear2); 848 849 return nYear2 - nYear1; 850 } 851 852 /** 853 * Check if a Date is in a leap year in the Gregorian calendar 854 */ 855 856 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear( 857 const uno::Reference< beans::XPropertySet >& xOptions, 858 sal_Int32 nDate ) 859 { 860 sal_Int32 nNullDate = GetNullDate( xOptions ); 861 sal_Int32 nDays = nDate + nNullDate; 862 863 sal_uInt16 nDay, nMonth, nYear; 864 DaysToDate(nDays,nDay,nMonth,nYear); 865 866 return (sal_Int32)IsLeapYear(nYear); 867 } 868 869 /** 870 * Get the Number of Days in the month for a date 871 */ 872 873 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth( 874 const uno::Reference<beans::XPropertySet>& xOptions, 875 sal_Int32 nDate ) 876 { 877 sal_Int32 nNullDate = GetNullDate( xOptions ); 878 sal_Int32 nDays = nDate + nNullDate; 879 880 sal_uInt16 nDay, nMonth, nYear; 881 DaysToDate(nDays,nDay,nMonth,nYear); 882 883 return DaysInMonth( nMonth, nYear ); 884 } 885 886 /** 887 * Get number of days in the year of a date specified 888 */ 889 890 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear( 891 const uno::Reference< beans::XPropertySet >& xOptions, 892 sal_Int32 nDate ) 893 { 894 sal_Int32 nNullDate = GetNullDate( xOptions ); 895 sal_Int32 nDays = nDate + nNullDate; 896 897 sal_uInt16 nDay, nMonth, nYear; 898 DaysToDate(nDays,nDay,nMonth,nYear); 899 900 return ( IsLeapYear(nYear) ? 366 : 365 ); 901 } 902 903 /** 904 * Get number of weeks in the year for a date 905 * 906 * Most years have 52 weeks, but years that start on a Thursday 907 * and leep years that start on a Wednesday have 53 weeks 908 * 909 * The International Standard IS-8601 has decreed that Monday 910 * shall be the first day of the week. 911 * 912 * A WeekDay can be calculated by subtracting 1 and calculating the rest of 913 * a division by 7 from the internal date represention 914 * which gives a 0 - 6 value for Monday - Sunday 915 * 916 * @see #IsLeapYear #WeekNumber 917 */ 918 919 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear( 920 const uno::Reference< beans::XPropertySet >& xOptions, 921 sal_Int32 nDate ) 922 { 923 sal_Int32 nNullDate = GetNullDate( xOptions ); 924 sal_Int32 nDays = nDate + nNullDate; 925 926 sal_uInt16 nDay, nMonth, nYear; 927 DaysToDate(nDays,nDay,nMonth,nYear); 928 929 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7; 930 931 sal_Int32 nRet; 932 if ( nJan1WeekDay == 3 ) /* Thursday */ 933 nRet = 53; 934 else if ( nJan1WeekDay == 2 ) /* Wednesday */ 935 nRet = ( IsLeapYear(nYear) ? 53 : 52 ); 936 else 937 nRet = 52; 938 939 return nRet; 940 } 941 942 /** 943 * Encrypt or decrypt a string using ROT13 algorithm 944 * 945 * This function rotates each character by 13 in the alphabet. 946 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified. 947 */ 948 949 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString ) 950 { 951 OUStringBuffer aBuffer( aSrcString ); 952 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ ) 953 { 954 sal_Unicode cChar = aBuffer.charAt( nIndex ); 955 if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) || 956 ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) ) 957 cChar -= 26; 958 aBuffer.setCharAt( nIndex, cChar ); 959 } 960 return aBuffer.makeStringAndClear(); 961 } 962 963 //------------------------------------------------------------------ 964