1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include "datefunc.hxx"
21 #include <datefunc.hrc>
22 #include <strings.hrc>
23 #include <com/sun/star/util/Date.hpp>
24 #include <cppuhelper/factory.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
27 #include <rtl/ustrbuf.hxx>
28 #include <unotools/resmgr.hxx>
29 #include <i18nlangtag/languagetag.hxx>
30 #include <algorithm>
31 #include "deffuncname.hxx"
32
33 using namespace ::com::sun::star;
34
35 #define ADDIN_SERVICE "com.sun.star.sheet.AddIn"
36 #define MY_SERVICE "com.sun.star.sheet.addin.DateFunctions"
37 #define MY_IMPLNAME "com.sun.star.sheet.addin.DateFunctionsImpl"
38
39 #define UNIQUE false // function name does not exist in Calc
40
41 #define STDPAR false // all parameters are described
42 #define INTPAR true // first parameter is internal
43
44 #define FUNCDATA( FuncName, ParamCount, Category, Double, IntPar ) \
45 { "get" #FuncName, DATE_FUNCNAME_##FuncName, DATE_FUNCDESC_##FuncName, DATE_DEFFUNCNAME_##FuncName, ParamCount, Category, Double, IntPar }
46
47 const ScaFuncDataBase pFuncDataArr[] =
48 {
49 FUNCDATA( DiffWeeks, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
50 FUNCDATA( DiffMonths, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
51 FUNCDATA( DiffYears, 3, ScaCategory::DateTime, UNIQUE, INTPAR ),
52 FUNCDATA( IsLeapYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
53 FUNCDATA( DaysInMonth, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
54 FUNCDATA( DaysInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
55 FUNCDATA( WeeksInYear, 1, ScaCategory::DateTime, UNIQUE, INTPAR ),
56 FUNCDATA( Rot13, 1, ScaCategory::Text, UNIQUE, STDPAR )
57 };
58
59 #undef FUNCDATA
60
ScaFuncData(const ScaFuncDataBase & rBaseData)61 ScaFuncData::ScaFuncData(const ScaFuncDataBase& rBaseData) :
62 aIntName( OUString::createFromAscii( rBaseData.pIntName ) ),
63 pUINameID( rBaseData.pUINameID ),
64 pDescrID( rBaseData.pDescrID ),
65 nParamCount( rBaseData.nParamCount ),
66 eCat( rBaseData.eCat ),
67 bDouble( rBaseData.bDouble ),
68 bWithOpt( rBaseData.bWithOpt )
69 {
70 aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[0]));
71 aCompList.push_back(OUString::createFromAscii(rBaseData.pCompListID[1]));
72 }
73
~ScaFuncData()74 ScaFuncData::~ScaFuncData()
75 {
76 }
77
GetStrIndex(sal_uInt16 nParam) const78 sal_uInt16 ScaFuncData::GetStrIndex( sal_uInt16 nParam ) const
79 {
80 if( !bWithOpt )
81 nParam++;
82 return (nParam > nParamCount) ? (nParamCount * 2) : (nParam * 2);
83 }
84
InitScaFuncDataList(ScaFuncDataList & rList)85 static void InitScaFuncDataList(ScaFuncDataList& rList)
86 {
87 for (const auto & nIndex : pFuncDataArr)
88 rList.push_back(ScaFuncData(nIndex));
89 }
90
91 // entry points for service registration / instantiation
ScaDateAddIn_CreateInstance(const uno::Reference<lang::XMultiServiceFactory> &)92 static uno::Reference< uno::XInterface > ScaDateAddIn_CreateInstance(
93 const uno::Reference< lang::XMultiServiceFactory >& )
94 {
95 return static_cast<cppu::OWeakObject*>(new ScaDateAddIn());
96 }
97
98 extern "C" {
99
date_component_getFactory(const sal_Char * pImplName,void * pServiceManager,void *)100 SAL_DLLPUBLIC_EXPORT void * date_component_getFactory(
101 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
102 {
103 void* pRet = nullptr;
104
105 if ( pServiceManager &&
106 OUString::createFromAscii( pImplName ) == ScaDateAddIn::getImplementationName_Static() )
107 {
108 uno::Reference< lang::XSingleServiceFactory > xFactory( cppu::createOneInstanceFactory(
109 static_cast< lang::XMultiServiceFactory* >( pServiceManager ),
110 ScaDateAddIn::getImplementationName_Static(),
111 ScaDateAddIn_CreateInstance,
112 ScaDateAddIn::getSupportedServiceNames_Static() ) );
113
114 if (xFactory.is())
115 {
116 xFactory->acquire();
117 pRet = xFactory.get();
118 }
119 }
120
121 return pRet;
122 }
123
124 } // extern C
125
126 // "normal" service implementation
ScaDateAddIn()127 ScaDateAddIn::ScaDateAddIn()
128 {
129 }
130
131 static const sal_Char* pLang[] = { "de", "en" };
132 static const sal_Char* pCoun[] = { "DE", "US" };
133 static const sal_uInt32 nNumOfLoc = SAL_N_ELEMENTS( pLang );
134
InitDefLocales()135 void ScaDateAddIn::InitDefLocales()
136 {
137 pDefLocales.reset(new lang::Locale[ nNumOfLoc ]);
138
139 for( sal_uInt32 nIndex = 0; nIndex < nNumOfLoc; nIndex++ )
140 {
141 pDefLocales[ nIndex ].Language = OUString::createFromAscii( pLang[ nIndex ] );
142 pDefLocales[ nIndex ].Country = OUString::createFromAscii( pCoun[ nIndex ] );
143 }
144 }
145
GetLocale(sal_uInt32 nIndex)146 const lang::Locale& ScaDateAddIn::GetLocale( sal_uInt32 nIndex )
147 {
148 if( !pDefLocales )
149 InitDefLocales();
150
151 return (nIndex < sizeof( pLang )) ? pDefLocales[ nIndex ] : aFuncLoc;
152 }
153
InitData()154 void ScaDateAddIn::InitData()
155 {
156 aResLocale = Translate::Create("sca", LanguageTag(aFuncLoc));
157 pFuncDataList.reset();
158
159 pFuncDataList.reset(new ScaFuncDataList);
160 InitScaFuncDataList(*pFuncDataList);
161
162 if( pDefLocales )
163 {
164 pDefLocales.reset();
165 }
166 }
167
GetFuncDescrStr(const char ** pResId,sal_uInt16 nStrIndex)168 OUString ScaDateAddIn::GetFuncDescrStr(const char** pResId, sal_uInt16 nStrIndex)
169 {
170 return ScaResId(pResId[nStrIndex - 1]);
171 }
172
getImplementationName_Static()173 OUString ScaDateAddIn::getImplementationName_Static()
174 {
175 return MY_IMPLNAME;
176 }
177
getSupportedServiceNames_Static()178 uno::Sequence< OUString > ScaDateAddIn::getSupportedServiceNames_Static()
179 {
180 return { ADDIN_SERVICE, MY_SERVICE };
181 }
182
183 // XServiceName
getServiceName()184 OUString SAL_CALL ScaDateAddIn::getServiceName()
185 {
186 // name of specific AddIn service
187 return MY_SERVICE;
188 }
189
190 // XServiceInfo
getImplementationName()191 OUString SAL_CALL ScaDateAddIn::getImplementationName()
192 {
193 return getImplementationName_Static();
194 }
195
supportsService(const OUString & aServiceName)196 sal_Bool SAL_CALL ScaDateAddIn::supportsService( const OUString& aServiceName )
197 {
198 return cppu::supportsService(this, aServiceName);
199 }
200
getSupportedServiceNames()201 uno::Sequence< OUString > SAL_CALL ScaDateAddIn::getSupportedServiceNames()
202 {
203 return getSupportedServiceNames_Static();
204 }
205
206 // XLocalizable
setLocale(const lang::Locale & eLocale)207 void SAL_CALL ScaDateAddIn::setLocale( const lang::Locale& eLocale )
208 {
209 aFuncLoc = eLocale;
210 InitData(); // change of locale invalidates resources!
211 }
212
getLocale()213 lang::Locale SAL_CALL ScaDateAddIn::getLocale()
214 {
215 return aFuncLoc;
216 }
217
getProgrammaticFuntionName(const OUString &)218 OUString SAL_CALL ScaDateAddIn::getProgrammaticFuntionName( const OUString& )
219 {
220 // not used by calc
221 // (but should be implemented for other uses of the AddIn service)
222 return OUString();
223 }
224
getDisplayFunctionName(const OUString & aProgrammaticName)225 OUString SAL_CALL ScaDateAddIn::getDisplayFunctionName( const OUString& aProgrammaticName )
226 {
227 OUString aRet;
228
229 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
230 FindScaFuncData( aProgrammaticName ) );
231 if( fDataIt != pFuncDataList->end() )
232 {
233 aRet = ScaResId(fDataIt->GetUINameID());
234 if( fDataIt->IsDouble() )
235 aRet += "_ADD";
236 }
237 else
238 {
239 aRet = "UNKNOWNFUNC_" + aProgrammaticName;
240 }
241
242 return aRet;
243 }
244
getFunctionDescription(const OUString & aProgrammaticName)245 OUString SAL_CALL ScaDateAddIn::getFunctionDescription( const OUString& aProgrammaticName )
246 {
247 OUString aRet;
248
249 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
250 FindScaFuncData( aProgrammaticName ) );
251 if( fDataIt != pFuncDataList->end() )
252 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), 1 );
253
254 return aRet;
255 }
256
getDisplayArgumentName(const OUString & aProgrammaticName,sal_Int32 nArgument)257 OUString SAL_CALL ScaDateAddIn::getDisplayArgumentName(
258 const OUString& aProgrammaticName, sal_Int32 nArgument )
259 {
260 OUString aRet;
261
262 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
263 FindScaFuncData( aProgrammaticName ) );
264 if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
265 {
266 sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
267 if( nStr )
268 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr );
269 else
270 aRet = "internal";
271 }
272
273 return aRet;
274 }
275
getArgumentDescription(const OUString & aProgrammaticName,sal_Int32 nArgument)276 OUString SAL_CALL ScaDateAddIn::getArgumentDescription(
277 const OUString& aProgrammaticName, sal_Int32 nArgument )
278 {
279 OUString aRet;
280
281 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
282 FindScaFuncData( aProgrammaticName ) );
283 if( fDataIt != pFuncDataList->end() && (nArgument <= 0xFFFF) )
284 {
285 sal_uInt16 nStr = fDataIt->GetStrIndex( static_cast< sal_uInt16 >( nArgument ) );
286 if( nStr )
287 aRet = GetFuncDescrStr( fDataIt->GetDescrID(), nStr + 1 );
288 else
289 aRet = "for internal use only";
290 }
291
292 return aRet;
293 }
294
getProgrammaticCategoryName(const OUString & aProgrammaticName)295 OUString SAL_CALL ScaDateAddIn::getProgrammaticCategoryName(
296 const OUString& aProgrammaticName )
297 {
298 OUString aRet;
299
300 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
301 FindScaFuncData( aProgrammaticName ) );
302 if( fDataIt != pFuncDataList->end() )
303 {
304 switch( fDataIt->GetCategory() )
305 {
306 case ScaCategory::DateTime: aRet = "Date&Time"; break;
307 case ScaCategory::Text: aRet = "Text"; break;
308 case ScaCategory::Finance: aRet = "Financial"; break;
309 case ScaCategory::Inf: aRet = "Information"; break;
310 case ScaCategory::Math: aRet = "Mathematical"; break;
311 case ScaCategory::Tech: aRet = "Technical"; break;
312 }
313 }
314
315 if( aRet.isEmpty() )
316 aRet = "Add-In";
317 return aRet;
318 }
319
getDisplayCategoryName(const OUString & aProgrammaticName)320 OUString SAL_CALL ScaDateAddIn::getDisplayCategoryName(
321 const OUString& aProgrammaticName )
322 {
323 return getProgrammaticCategoryName( aProgrammaticName );
324 }
325
326 // XCompatibilityNames
getCompatibilityNames(const OUString & aProgrammaticName)327 uno::Sequence< sheet::LocalizedName > SAL_CALL ScaDateAddIn::getCompatibilityNames(
328 const OUString& aProgrammaticName )
329 {
330 auto fDataIt = std::find_if(pFuncDataList->begin(), pFuncDataList->end(),
331 FindScaFuncData( aProgrammaticName ) );
332 if( fDataIt == pFuncDataList->end() )
333 return uno::Sequence< sheet::LocalizedName >( 0 );
334
335 const std::vector<OUString>& rStrList = fDataIt->GetCompNameList();
336 sal_uInt32 nCount = rStrList.size();
337
338 uno::Sequence< sheet::LocalizedName > aRet( nCount );
339 sheet::LocalizedName* pArray = aRet.getArray();
340
341 for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ )
342 pArray[ nIndex ] = sheet::LocalizedName( GetLocale( nIndex ), rStrList.at( nIndex ) );
343
344 return aRet;
345 }
346
347 namespace {
348
349 // auxiliary functions
IsLeapYear(sal_uInt16 nYear)350 bool IsLeapYear( sal_uInt16 nYear )
351 {
352 return ((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
353 }
354
DaysInMonth(sal_uInt16 nMonth,sal_uInt16 nYear)355 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
356 {
357 static const sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
358 31, 31, 30, 31, 30, 31 };
359
360 if ( nMonth != 2 )
361 return aDaysInMonth[nMonth-1];
362 else
363 {
364 if ( IsLeapYear(nYear) )
365 return aDaysInMonth[nMonth-1] + 1;
366 else
367 return aDaysInMonth[nMonth-1];
368 }
369 }
370
371 /**
372 * Convert a date to a count of days starting from 01/01/0001
373 *
374 * The internal representation of a Date used in this Addin
375 * is the number of days between 01/01/0001 and the date
376 * this function converts a Day , Month, Year representation
377 * to this internal Date value.
378 */
379
DateToDays(sal_uInt16 nDay,sal_uInt16 nMonth,sal_uInt16 nYear)380 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
381 {
382 sal_Int32 nDays = (static_cast<sal_Int32>(nYear)-1) * 365;
383 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
384
385 for( sal_uInt16 i = 1; i < nMonth; i++ )
386 nDays += DaysInMonth(i,nYear);
387 nDays += nDay;
388
389 return nDays;
390 }
391
392 /**
393 * Convert a count of days starting from 01/01/0001 to a date
394 *
395 * The internal representation of a Date used in this Addin
396 * is the number of days between 01/01/0001 and the date
397 * this function converts this internal Date value
398 * to a Day , Month, Year representation of a Date.
399 *
400 * @throws lang::IllegalArgumentException
401 */
402
DaysToDate(sal_Int32 nDays,sal_uInt16 & rDay,sal_uInt16 & rMonth,sal_uInt16 & rYear)403 void DaysToDate( sal_Int32 nDays,
404 sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
405 {
406 if( nDays < 0 )
407 throw lang::IllegalArgumentException();
408
409 sal_Int32 nTempDays;
410 sal_Int32 i = 0;
411 bool bCalc;
412
413 do
414 {
415 nTempDays = nDays;
416 rYear = static_cast<sal_uInt16>((nTempDays / 365) - i);
417 nTempDays -= (static_cast<sal_Int32>(rYear) -1) * 365;
418 nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
419 bCalc = false;
420 if ( nTempDays < 1 )
421 {
422 i++;
423 bCalc = true;
424 }
425 else
426 {
427 if ( nTempDays > 365 )
428 {
429 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
430 {
431 i--;
432 bCalc = true;
433 }
434 }
435 }
436 }
437 while ( bCalc );
438
439 rMonth = 1;
440 while ( nTempDays > DaysInMonth( rMonth, rYear ) )
441 {
442 nTempDays -= DaysInMonth( rMonth, rYear );
443 rMonth++;
444 }
445 rDay = static_cast<sal_uInt16>(nTempDays);
446 }
447
448 /**
449 * Get the null date used by the spreadsheet document
450 *
451 * The internal representation of a Date used in this Addin
452 * is the number of days between 01/01/0001 and the date
453 * this function returns this internal Date value for the document null date
454 *
455 * @throws uno::RuntimeException
456 */
GetNullDate(const uno::Reference<beans::XPropertySet> & xOptions)457 sal_Int32 GetNullDate( const uno::Reference< beans::XPropertySet >& xOptions )
458 {
459 if (xOptions.is())
460 {
461 try
462 {
463 uno::Any aAny = xOptions->getPropertyValue( "NullDate" );
464 util::Date aDate;
465 if ( aAny >>= aDate )
466 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
467 }
468 catch (uno::Exception&)
469 {
470 }
471 }
472
473 // no null date available -> no calculations possible
474 throw uno::RuntimeException();
475 }
476
477 }
478 // XDateFunctions
479
480 /**
481 * Get week difference between 2 dates
482 *
483 * new Weeks(date1,date2,mode) function for StarCalc
484 *
485 * Two modes of operation are provided.
486 * The first is just a simple division by 7 calculation.
487 *
488 * The second calculates the difference by week of year.
489 *
490 * The International Standard IS-8601 has decreed that Monday
491 * shall be the first day of the week.
492 *
493 * A week that lies partly in one year and partly in another
494 * is assigned a number in the year in which most of its days lie.
495 *
496 * That means that week 1 of any year is the week that contains the 4. January
497 *
498 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
499 *
500 * A WeekDay can be then calculated by subtracting 1 and calculating the rest of
501 * a division by 7, which gives a 0 - 6 value for Monday - Sunday
502 *
503 * Using the 4. January rule explained above the formula
504 *
505 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
506 *
507 * calculates a number between 0-53 for each day which is in the same year as nJan4
508 * where 0 means that this week belonged to the year before.
509 *
510 * If a day in the same or another year is used in this formula this calculates
511 * a calendar week offset from a given 4. January
512 *
513 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
514 *
515 * The 4.January of first Date Argument can thus be used to calculate
516 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
517 *
518 * which can be optimized to
519 *
520 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
521 *
522 * Note: All calculations are operating on the long integer data type
523 * % is the modulo operator in C which calculates the rest of an Integer division
524 *
525 *
526 * mode 0 is the interval between the dates in month, that is days / 7
527 *
528 * mode 1 is the difference by week of year
529 *
530 */
531
getDiffWeeks(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nStartDate,sal_Int32 nEndDate,sal_Int32 nMode)532 sal_Int32 SAL_CALL ScaDateAddIn::getDiffWeeks(
533 const uno::Reference< beans::XPropertySet >& xOptions,
534 sal_Int32 nStartDate, sal_Int32 nEndDate,
535 sal_Int32 nMode )
536 {
537 if (nMode != 0 && nMode != 1)
538 throw lang::IllegalArgumentException();
539
540 sal_Int32 nNullDate = GetNullDate( xOptions );
541
542 sal_Int32 nDays1 = nStartDate + nNullDate;
543 sal_Int32 nDays2 = nEndDate + nNullDate;
544
545 sal_Int32 nRet;
546
547 if ( nMode == 1 )
548 {
549 sal_uInt16 nDay,nMonth,nYear;
550 DaysToDate( nDays1, nDay, nMonth, nYear );
551 sal_Int32 nJan4 = DateToDays( 4, 1, nYear );
552
553 nRet = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 );
554 }
555 else
556 {
557 nRet = (nDays2 - nDays1) / 7;
558 }
559 return nRet;
560 }
561
562 /**
563 * Get month difference between 2 dates
564 * =Month(start, end, mode) Function for StarCalc
565 *
566 * two modes are provided
567 *
568 * mode 0 is the interval between the dates in month
569 *
570 * mode 1 is the difference in calendar month
571 */
getDiffMonths(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nStartDate,sal_Int32 nEndDate,sal_Int32 nMode)572 sal_Int32 SAL_CALL ScaDateAddIn::getDiffMonths(
573 const uno::Reference< beans::XPropertySet >& xOptions,
574 sal_Int32 nStartDate, sal_Int32 nEndDate,
575 sal_Int32 nMode )
576 {
577 if (nMode != 0 && nMode != 1)
578 throw lang::IllegalArgumentException();
579
580 sal_Int32 nNullDate = GetNullDate( xOptions );
581
582 sal_Int32 nDays1 = nStartDate + nNullDate;
583 sal_Int32 nDays2 = nEndDate + nNullDate;
584
585 sal_uInt16 nDay1,nMonth1,nYear1;
586 sal_uInt16 nDay2,nMonth2,nYear2;
587 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
588 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
589
590 sal_Int32 nRet = nMonth2 - nMonth1 + (nYear2 - nYear1) * 12;
591 if ( nMode == 1 || nDays1 == nDays2 ) return nRet;
592
593 if ( nDays1 < nDays2 )
594 {
595 if ( nDay1 > nDay2 )
596 {
597 nRet -= 1;
598 }
599 }
600 else
601 {
602 if ( nDay1 < nDay2 )
603 {
604 nRet += 1;
605 }
606 }
607
608 return nRet;
609 }
610
611 /**
612 * Get Year difference between 2 dates
613 *
614 * two modes are provided
615 *
616 * mode 0 is the interval between the dates in years
617 *
618 * mode 1 is the difference in calendar years
619 */
getDiffYears(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nStartDate,sal_Int32 nEndDate,sal_Int32 nMode)620 sal_Int32 SAL_CALL ScaDateAddIn::getDiffYears(
621 const uno::Reference< beans::XPropertySet >& xOptions,
622 sal_Int32 nStartDate, sal_Int32 nEndDate,
623 sal_Int32 nMode )
624 {
625 if (nMode != 0 && nMode != 1)
626 throw lang::IllegalArgumentException();
627
628 if ( nMode != 1 )
629 return getDiffMonths( xOptions, nStartDate, nEndDate, nMode ) / 12;
630
631 sal_Int32 nNullDate = GetNullDate( xOptions );
632
633 sal_Int32 nDays1 = nStartDate + nNullDate;
634 sal_Int32 nDays2 = nEndDate + nNullDate;
635
636 sal_uInt16 nDay1,nMonth1,nYear1;
637 sal_uInt16 nDay2,nMonth2,nYear2;
638 DaysToDate(nDays1,nDay1,nMonth1,nYear1);
639 DaysToDate(nDays2,nDay2,nMonth2,nYear2);
640
641 return nYear2 - nYear1;
642 }
643
644 /**
645 * Check if a Date is in a leap year in the Gregorian calendar
646 */
getIsLeapYear(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nDate)647 sal_Int32 SAL_CALL ScaDateAddIn::getIsLeapYear(
648 const uno::Reference< beans::XPropertySet >& xOptions,
649 sal_Int32 nDate )
650 {
651 sal_Int32 nNullDate = GetNullDate( xOptions );
652 sal_Int32 nDays = nDate + nNullDate;
653
654 sal_uInt16 nDay, nMonth, nYear;
655 DaysToDate(nDays,nDay,nMonth,nYear);
656
657 return static_cast<sal_Int32>(IsLeapYear(nYear));
658 }
659
660 /**
661 * Get the Number of Days in the month for a date
662 */
getDaysInMonth(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nDate)663 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInMonth(
664 const uno::Reference<beans::XPropertySet>& xOptions,
665 sal_Int32 nDate )
666 {
667 sal_Int32 nNullDate = GetNullDate( xOptions );
668 sal_Int32 nDays = nDate + nNullDate;
669
670 sal_uInt16 nDay, nMonth, nYear;
671 DaysToDate(nDays,nDay,nMonth,nYear);
672
673 return DaysInMonth( nMonth, nYear );
674 }
675
676 /**
677 * Get number of days in the year of a date specified
678 */
getDaysInYear(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nDate)679 sal_Int32 SAL_CALL ScaDateAddIn::getDaysInYear(
680 const uno::Reference< beans::XPropertySet >& xOptions,
681 sal_Int32 nDate )
682 {
683 sal_Int32 nNullDate = GetNullDate( xOptions );
684 sal_Int32 nDays = nDate + nNullDate;
685
686 sal_uInt16 nDay, nMonth, nYear;
687 DaysToDate(nDays,nDay,nMonth,nYear);
688
689 return ( IsLeapYear(nYear) ? 366 : 365 );
690 }
691
692 /**
693 * Get number of weeks in the year for a date
694 *
695 * Most years have 52 weeks, but years that start on a Thursday
696 * and leap years that start on a Wednesday have 53 weeks
697 *
698 * The International Standard IS-8601 has decreed that Monday
699 * shall be the first day of the week.
700 *
701 * A WeekDay can be calculated by subtracting 1 and calculating the rest of
702 * a division by 7 from the internal date representation
703 * which gives a 0 - 6 value for Monday - Sunday
704 *
705 * @see #IsLeapYear #WeekNumber
706 */
getWeeksInYear(const uno::Reference<beans::XPropertySet> & xOptions,sal_Int32 nDate)707 sal_Int32 SAL_CALL ScaDateAddIn::getWeeksInYear(
708 const uno::Reference< beans::XPropertySet >& xOptions,
709 sal_Int32 nDate )
710 {
711 sal_Int32 nNullDate = GetNullDate( xOptions );
712 sal_Int32 nDays = nDate + nNullDate;
713
714 sal_uInt16 nDay, nMonth, nYear;
715 DaysToDate(nDays,nDay,nMonth,nYear);
716
717 sal_Int32 nJan1WeekDay = ( DateToDays(1,1,nYear) - 1) % 7;
718
719 sal_Int32 nRet;
720 if ( nJan1WeekDay == 3 ) /* Thursday */
721 nRet = 53;
722 else if ( nJan1WeekDay == 2 ) /* Wednesday */
723 nRet = ( IsLeapYear(nYear) ? 53 : 52 );
724 else
725 nRet = 52;
726
727 return nRet;
728 }
729
730 /**
731 * Encrypt or decrypt a string using ROT13 algorithm
732 *
733 * This function rotates each character by 13 in the alphabet.
734 * Only the characters 'a' ... 'z' and 'A' ... 'Z' are modified.
735 */
getRot13(const OUString & aSrcString)736 OUString SAL_CALL ScaDateAddIn::getRot13( const OUString& aSrcString )
737 {
738 OUStringBuffer aBuffer( aSrcString );
739 for( sal_Int32 nIndex = 0; nIndex < aBuffer.getLength(); nIndex++ )
740 {
741 sal_Unicode cChar = aBuffer[nIndex];
742 if( ((cChar >= 'a') && (cChar <= 'z') && ((cChar += 13) > 'z')) ||
743 ((cChar >= 'A') && (cChar <= 'Z') && ((cChar += 13) > 'Z')) )
744 cChar -= 26;
745 aBuffer[nIndex] = cChar;
746 }
747 return aBuffer.makeStringAndClear();
748 }
749
ScaResId(const char * pId)750 OUString ScaDateAddIn::ScaResId(const char* pId)
751 {
752 return Translate::get(pId, aResLocale);
753 }
754
755 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
756