Coverage Report

Created: 2025-07-07 10:01

/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: */