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