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