xref: /aoo41x/main/sc/addin/datefunc/dfa.cl (revision cdf0e10c)
1*cdf0e10cSrcweir/*************************************************************************
2*cdf0e10cSrcweir *
3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir *
5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir *
7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir *
9*cdf0e10cSrcweir * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir *
11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir *
15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir *
21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir *
26*cdf0e10cSrcweir ************************************************************************/
27*cdf0e10cSrcweir
28*cdf0e10cSrcweir/* static char datefunc_Id[]="@(#) StarCalc Datefunc AddIn (c) 1998-2000 Sun Microsystems, Inc."; */
29*cdf0e10cSrcweir
30*cdf0e10cSrcweir#include <string.h>
31*cdf0e10cSrcweir#include <stdlib.h>
32*cdf0e10cSrcweir#include <math.h>
33*cdf0e10cSrcweir
34*cdf0e10cSrcweir#include <xlang.h>
35*cdf0e10cSrcweir#include <addin.h>
36*cdf0e10cSrcweir#include <dfa.hrc>
37*cdf0e10cSrcweir
38*cdf0e10cSrcweir
39*cdf0e10cSrcweir/**
40*cdf0e10cSrcweir * the current language the Addin is using
41*cdf0e10cSrcweir */
42*cdf0e10cSrcweirstatic USHORT _nLanguage=LANGUAGE_ENGLISH;
43*cdf0e10cSrcweir
44*cdf0e10cSrcweir/**
45*cdf0e10cSrcweir * StarCalc calls this function to set a new current Language for the Addin
46*cdf0e10cSrcweir *
47*cdf0e10cSrcweir * @param *nLanguage
48*cdf0e10cSrcweir *
49*cdf0e10cSrcweir */
50*cdf0e10cSrcweirvoid CALLTYPE SetLanguage( USHORT* nLanguage )
51*cdf0e10cSrcweir{
52*cdf0e10cSrcweir	_nLanguage = GetNeutralLanguage( *nLanguage );
53*cdf0e10cSrcweir}
54*cdf0e10cSrcweir
55*cdf0e10cSrcweir
56*cdf0e10cSrcweir/**
57*cdf0e10cSrcweir * Null Date, initialized in GetFunctionCount
58*cdf0e10cSrcweir *
59*cdf0e10cSrcweir * StarCalc uses a BaseDate 12/30/1899
60*cdf0e10cSrcweir * If not specified otherwise in the Settings for the Spreedsheet Document.
61*cdf0e10cSrcweir *
62*cdf0e10cSrcweir * There's no way to get the Spreadsheet settings from whithin a simple addin,
63*cdf0e10cSrcweir * so this Addin can only be used by documents using the default BaseDate setting.
64*cdf0e10cSrcweir *
65*cdf0e10cSrcweir * The functions in this Addin use a BaseDate 01/01/0001
66*cdf0e10cSrcweir * The nNullDate Variable is the StarCalc BaseDate converted to
67*cdf0e10cSrcweir * this internal date representation.
68*cdf0e10cSrcweir *
69*cdf0e10cSrcweir * @see #GetFunctionCount
70*cdf0e10cSrcweir *
71*cdf0e10cSrcweir */
72*cdf0e10cSrcweir
73*cdf0e10cSrcweirstatic ULONG nNullDate=0;
74*cdf0e10cSrcweir
75*cdf0e10cSrcweir#define NULLDATE_Year  1899
76*cdf0e10cSrcweir#define NULLDATE_Month 12
77*cdf0e10cSrcweir#define NULLDATE_Day   30
78*cdf0e10cSrcweir
79*cdf0e10cSrcweir
80*cdf0e10cSrcweir/**
81*cdf0e10cSrcweir * Array holding values for month length, used in DaysInMonth() function
82*cdf0e10cSrcweir *
83*cdf0e10cSrcweir * @see #DaysInMonth
84*cdf0e10cSrcweir *
85*cdf0e10cSrcweir */
86*cdf0e10cSrcweirstatic USHORT aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
87*cdf0e10cSrcweir                                   31, 31, 30, 31, 30, 31 };
88*cdf0e10cSrcweir
89*cdf0e10cSrcweir/**
90*cdf0e10cSrcweir * Check if a year is a leap year in the Gregorian calendar
91*cdf0e10cSrcweir *
92*cdf0e10cSrcweir * @param nYear the year which should be checked
93*cdf0e10cSrcweir * @return true if the year is a leap year, false otherwise.
94*cdf0e10cSrcweir *
95*cdf0e10cSrcweir * @see #DaysInMonth, #IsLeapYear,
96*cdf0e10cSrcweir * @see #ScDate_DaysInMonth, #ScDate_IsLeapYear, #ScDate_WeeksInYear
97*cdf0e10cSrcweir *
98*cdf0e10cSrcweir */
99*cdf0e10cSrcweirstatic BOOL IsLeapYear( USHORT nYear )
100*cdf0e10cSrcweir{
101*cdf0e10cSrcweir    return (BOOL)((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
102*cdf0e10cSrcweir}
103*cdf0e10cSrcweir
104*cdf0e10cSrcweir
105*cdf0e10cSrcweir/**
106*cdf0e10cSrcweir * Get the number of days in a specified month
107*cdf0e10cSrcweir *
108*cdf0e10cSrcweir * @param nMonth the number of the Month
109*cdf0e10cSrcweir * @param nYear the year
110*cdf0e10cSrcweir * @return number of days
111*cdf0e10cSrcweir *
112*cdf0e10cSrcweir */
113*cdf0e10cSrcweirstatic USHORT DaysInMonth( USHORT nMonth, USHORT nYear )
114*cdf0e10cSrcweir{
115*cdf0e10cSrcweir    if ( nMonth != 2 )
116*cdf0e10cSrcweir        return aDaysInMonth[nMonth-1];
117*cdf0e10cSrcweir    else
118*cdf0e10cSrcweir    {
119*cdf0e10cSrcweir        if ( IsLeapYear(nYear) )
120*cdf0e10cSrcweir            return aDaysInMonth[nMonth-1] + 1;
121*cdf0e10cSrcweir        else
122*cdf0e10cSrcweir            return aDaysInMonth[nMonth-1];
123*cdf0e10cSrcweir    }
124*cdf0e10cSrcweir}
125*cdf0e10cSrcweir
126*cdf0e10cSrcweir
127*cdf0e10cSrcweir/**
128*cdf0e10cSrcweir * Convert a date to a count of days starting from 01/01/0001
129*cdf0e10cSrcweir *
130*cdf0e10cSrcweir * The internal representation of a Date used in this Addin
131*cdf0e10cSrcweir * is the number of days between 01/01/0001 and the date
132*cdf0e10cSrcweir * this function converts a Day , Month, Year representation
133*cdf0e10cSrcweir * to this internal Date value.
134*cdf0e10cSrcweir *
135*cdf0e10cSrcweir * @param nDay the day of the Month
136*cdf0e10cSrcweir * @param nMonth the number of the Month
137*cdf0e10cSrcweir * @param nYear the Year
138*cdf0e10cSrcweir * @return count of days from 01/01/0001 to the date specified
139*cdf0e10cSrcweir *
140*cdf0e10cSrcweir */
141*cdf0e10cSrcweirstatic long DateToDays( USHORT nDay, USHORT nMonth, USHORT nYear )
142*cdf0e10cSrcweir{
143*cdf0e10cSrcweir    long nDays;
144*cdf0e10cSrcweir    USHORT i;
145*cdf0e10cSrcweir
146*cdf0e10cSrcweir    nDays = ((ULONG)nYear-1) * 365;
147*cdf0e10cSrcweir    nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
148*cdf0e10cSrcweir
149*cdf0e10cSrcweir    for( i = 1; i < nMonth; i++ )
150*cdf0e10cSrcweir        nDays += DaysInMonth(i,nYear);
151*cdf0e10cSrcweir    nDays += nDay;
152*cdf0e10cSrcweir
153*cdf0e10cSrcweir    return nDays;
154*cdf0e10cSrcweir}
155*cdf0e10cSrcweir
156*cdf0e10cSrcweir
157*cdf0e10cSrcweir/**
158*cdf0e10cSrcweir * Convert a count of days starting from 01/01/0001 to a date
159*cdf0e10cSrcweir *
160*cdf0e10cSrcweir * The internal representation of a Date used in this Addin
161*cdf0e10cSrcweir * is the number of days between 01/01/0001 and the date
162*cdf0e10cSrcweir * this function converts this internal Date value
163*cdf0e10cSrcweir * to a Day , Month, Year representation of a Date.
164*cdf0e10cSrcweir *
165*cdf0e10cSrcweir * @param nDay count of days from 01/01/0001
166*cdf0e10cSrcweir * @param *pDay pointer to a variable for the day of the month
167*cdf0e10cSrcweir * @param *pMonth pointer to a variable for the month
168*cdf0e10cSrcweir * @param *pYear pointer to a variable for the year
169*cdf0e10cSrcweir *
170*cdf0e10cSrcweir */
171*cdf0e10cSrcweirstatic void DaysToDate( long nDays,
172*cdf0e10cSrcweir                        USHORT *pDay, USHORT *pMonth, USHORT *pYear )
173*cdf0e10cSrcweir{
174*cdf0e10cSrcweir    long    nTempDays;
175*cdf0e10cSrcweir    long    i = 0;
176*cdf0e10cSrcweir    BOOL    bCalc;
177*cdf0e10cSrcweir
178*cdf0e10cSrcweir    do
179*cdf0e10cSrcweir    {
180*cdf0e10cSrcweir        nTempDays = (long)nDays;
181*cdf0e10cSrcweir        *pYear = (USHORT)((nTempDays / 365) - i);
182*cdf0e10cSrcweir        nTempDays -= ((ULONG) *pYear -1) * 365;
183*cdf0e10cSrcweir        nTempDays -= (( *pYear -1) / 4) - (( *pYear -1) / 100) + ((*pYear -1) / 400);
184*cdf0e10cSrcweir        bCalc = FALSE;
185*cdf0e10cSrcweir        if ( nTempDays < 1 )
186*cdf0e10cSrcweir        {
187*cdf0e10cSrcweir            i++;
188*cdf0e10cSrcweir            bCalc = TRUE;
189*cdf0e10cSrcweir        }
190*cdf0e10cSrcweir        else
191*cdf0e10cSrcweir        {
192*cdf0e10cSrcweir            if ( nTempDays > 365 )
193*cdf0e10cSrcweir            {
194*cdf0e10cSrcweir                if ( (nTempDays != 366) || !IsLeapYear( *pYear ) )
195*cdf0e10cSrcweir                {
196*cdf0e10cSrcweir                    i--;
197*cdf0e10cSrcweir                    bCalc = TRUE;
198*cdf0e10cSrcweir                }
199*cdf0e10cSrcweir            }
200*cdf0e10cSrcweir        }
201*cdf0e10cSrcweir    }
202*cdf0e10cSrcweir    while ( bCalc );
203*cdf0e10cSrcweir
204*cdf0e10cSrcweir    *pMonth = 1;
205*cdf0e10cSrcweir    while ( (ULONG)nTempDays > DaysInMonth( *pMonth, *pYear ) )
206*cdf0e10cSrcweir    {
207*cdf0e10cSrcweir        nTempDays -= DaysInMonth( *pMonth, *pYear );
208*cdf0e10cSrcweir        (*pMonth)++;
209*cdf0e10cSrcweir    }
210*cdf0e10cSrcweir    *pDay = (USHORT)nTempDays;
211*cdf0e10cSrcweir}
212*cdf0e10cSrcweir
213*cdf0e10cSrcweir/**
214*cdf0e10cSrcweir * Get week difference between 2 dates
215*cdf0e10cSrcweir *
216*cdf0e10cSrcweir * new Weeks(date1,date2,mode) function for StarCalc
217*cdf0e10cSrcweir *
218*cdf0e10cSrcweir * Two modes of operation are provided.
219*cdf0e10cSrcweir * The first is just a simple division by 7 calculation.
220*cdf0e10cSrcweir *
221*cdf0e10cSrcweir * The second calculates the diffence by week of year.
222*cdf0e10cSrcweir *
223*cdf0e10cSrcweir * The International Standard IS-8601 has decreed that Monday
224*cdf0e10cSrcweir * shall be the first day of the week.
225*cdf0e10cSrcweir *
226*cdf0e10cSrcweir * A week that lies partly in one year and partly in annother
227*cdf0e10cSrcweir * is assigned a number in the the year in which most of its days lie.
228*cdf0e10cSrcweir *
229*cdf0e10cSrcweir * That means that week 1 of any year is the week that contains the 4. January
230*cdf0e10cSrcweir *
231*cdf0e10cSrcweir * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
232*cdf0e10cSrcweir *
233*cdf0e10cSrcweir * A WeekDay can be then calculated by substracting 1 and calculating the rest of
234*cdf0e10cSrcweir * a division by 7, which gives a 0 - 6 value for Monday - Sunday
235*cdf0e10cSrcweir *
236*cdf0e10cSrcweir * Using the 4. January rule explained above the formula
237*cdf0e10cSrcweir *
238*cdf0e10cSrcweir *	nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
239*cdf0e10cSrcweir *
240*cdf0e10cSrcweir * calculates a number between 0-53 for each day which is in the same year as nJan4
241*cdf0e10cSrcweir * where 0 means that this week belonged to the year before.
242*cdf0e10cSrcweir *
243*cdf0e10cSrcweir * If a day in the same or annother year is used in this formula this calculates
244*cdf0e10cSrcweir * an calendar week offset from a given 4. January
245*cdf0e10cSrcweir *
246*cdf0e10cSrcweir *	nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
247*cdf0e10cSrcweir *
248*cdf0e10cSrcweir * The 4.January of first Date Argument can thus be used to calculate
249*cdf0e10cSrcweir * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
250*cdf0e10cSrcweir *
251*cdf0e10cSrcweir * which can be optimized to
252*cdf0e10cSrcweir *
253*cdf0e10cSrcweir * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
254*cdf0e10cSrcweir *
255*cdf0e10cSrcweir * Note: All calculations are operating on the long integer data type
256*cdf0e10cSrcweir * % is the modulo operator in C which calculates the rest of an Integer division
257*cdf0e10cSrcweir *
258*cdf0e10cSrcweir *
259*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
260*cdf0e10cSrcweir * @param d1 - date value (in StarCalc representation based 12/30/1899), usually the older date
261*cdf0e10cSrcweir * @param d2 - date value (in StarCalc representation based 12/30/1899), usually the younger date
262*cdf0e10cSrcweir * @param dMode - mode of operation
263*cdf0e10cSrcweir *
264*cdf0e10cSrcweir * mode 0 is the interval between the dates in month, that is days / 7
265*cdf0e10cSrcweir *
266*cdf0e10cSrcweir * mode 1 is the difference by week of year
267*cdf0e10cSrcweir *
268*cdf0e10cSrcweir */
269*cdf0e10cSrcweirvoid CALLTYPE ScDate_GetDiffWeeks(double *r, double *d1, double *d2, double *dMode)
270*cdf0e10cSrcweir{
271*cdf0e10cSrcweir  long nDays1=0;
272*cdf0e10cSrcweir  long nDays2=0;
273*cdf0e10cSrcweir  int nMode=0;
274*cdf0e10cSrcweir
275*cdf0e10cSrcweir  if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
276*cdf0e10cSrcweir  if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
277*cdf0e10cSrcweir
278*cdf0e10cSrcweir
279*cdf0e10cSrcweir  if ( dMode) nMode=(int)*dMode;
280*cdf0e10cSrcweir
281*cdf0e10cSrcweir  if ( nMode == 1 ) {
282*cdf0e10cSrcweir
283*cdf0e10cSrcweir	USHORT nDay,nMonth,nYear;
284*cdf0e10cSrcweir	long nJan4;
285*cdf0e10cSrcweir
286*cdf0e10cSrcweir	DaysToDate(nDays1,&nDay,&nMonth,&nYear);
287*cdf0e10cSrcweir	nJan4=DateToDays(4,1,nYear);
288*cdf0e10cSrcweir
289*cdf0e10cSrcweir	*r=(double) ( ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) );
290*cdf0e10cSrcweir
291*cdf0e10cSrcweir  } else {
292*cdf0e10cSrcweir
293*cdf0e10cSrcweir	*r= (double) ( (nDays2 - nDays1) / 7 ) ;
294*cdf0e10cSrcweir  }
295*cdf0e10cSrcweir
296*cdf0e10cSrcweir}
297*cdf0e10cSrcweir
298*cdf0e10cSrcweir/**
299*cdf0e10cSrcweir * Get month difference between 2 dates
300*cdf0e10cSrcweir * =Month(start, end, mode) Function for StarCalc
301*cdf0e10cSrcweir *
302*cdf0e10cSrcweir * two modes are provided
303*cdf0e10cSrcweir *
304*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
305*cdf0e10cSrcweir * @param d1 - date value, start date
306*cdf0e10cSrcweir * @param d2 - date value, end date
307*cdf0e10cSrcweir * @param dMode - mode of operation
308*cdf0e10cSrcweir *
309*cdf0e10cSrcweir * mode 0 is the interval between the dates in month
310*cdf0e10cSrcweir *
311*cdf0e10cSrcweir * mode 1 is the difference in calendar month
312*cdf0e10cSrcweir *
313*cdf0e10cSrcweir */
314*cdf0e10cSrcweirvoid CALLTYPE ScDate_GetDiffMonths(double *r, double *d1, double *d2, double *dMode)
315*cdf0e10cSrcweir{
316*cdf0e10cSrcweir  USHORT nDay1,nMonth1,nYear1;
317*cdf0e10cSrcweir  USHORT nDay2,nMonth2,nYear2;
318*cdf0e10cSrcweir  long nDays1=0;
319*cdf0e10cSrcweir  long nDays2=0;
320*cdf0e10cSrcweir  int nMode=0;
321*cdf0e10cSrcweir
322*cdf0e10cSrcweir  if ( dMode) nMode=(int)*dMode;
323*cdf0e10cSrcweir
324*cdf0e10cSrcweir  if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
325*cdf0e10cSrcweir  if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
326*cdf0e10cSrcweir
327*cdf0e10cSrcweir  DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
328*cdf0e10cSrcweir  DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
329*cdf0e10cSrcweir
330*cdf0e10cSrcweir  *r=(double) ( nMonth2 - nMonth1 + (nYear2 - nYear1) * 12 );
331*cdf0e10cSrcweir  if ( nMode == 1 || nDays1 == nDays2 ) return;
332*cdf0e10cSrcweir
333*cdf0e10cSrcweir  if ( nDays1 < nDays2 ) {
334*cdf0e10cSrcweir	if ( nDay1 > nDay2 ) {
335*cdf0e10cSrcweir		*r -= 1;
336*cdf0e10cSrcweir	}
337*cdf0e10cSrcweir  } else {
338*cdf0e10cSrcweir	if ( nDay1 < nDay2 ) {
339*cdf0e10cSrcweir		*r += 1;
340*cdf0e10cSrcweir	}
341*cdf0e10cSrcweir  }
342*cdf0e10cSrcweir
343*cdf0e10cSrcweir}
344*cdf0e10cSrcweir
345*cdf0e10cSrcweir
346*cdf0e10cSrcweir/**
347*cdf0e10cSrcweir * Get Year difference between 2 dates
348*cdf0e10cSrcweir *
349*cdf0e10cSrcweir * two modes are provided
350*cdf0e10cSrcweir *
351*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
352*cdf0e10cSrcweir * @param d1 - date value, start date
353*cdf0e10cSrcweir * @param d2 - date value, end date
354*cdf0e10cSrcweir * @param dMode - mode of operation
355*cdf0e10cSrcweir *
356*cdf0e10cSrcweir * mode 0 is the interval between the dates in years
357*cdf0e10cSrcweir *
358*cdf0e10cSrcweir * mode 1 is the difference in calendar years
359*cdf0e10cSrcweir *
360*cdf0e10cSrcweir */
361*cdf0e10cSrcweirvoid CALLTYPE ScDate_GetDiffYears(double *r, double *d1, double *d2, double *dMode)
362*cdf0e10cSrcweir{
363*cdf0e10cSrcweir  USHORT nDay1,nMonth1,nYear1;
364*cdf0e10cSrcweir  USHORT nDay2,nMonth2,nYear2;
365*cdf0e10cSrcweir  long nDays1=0;
366*cdf0e10cSrcweir  long nDays2=0;
367*cdf0e10cSrcweir  int nMode=0;
368*cdf0e10cSrcweir
369*cdf0e10cSrcweir  if ( dMode) nMode=(int)*dMode;
370*cdf0e10cSrcweir
371*cdf0e10cSrcweir  if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
372*cdf0e10cSrcweir  if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
373*cdf0e10cSrcweir
374*cdf0e10cSrcweir  DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
375*cdf0e10cSrcweir  DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
376*cdf0e10cSrcweir  if ( nMode != 1 ) {
377*cdf0e10cSrcweir	ScDate_GetDiffMonths(r,d1,d2,dMode);
378*cdf0e10cSrcweir	*r= (double) ( ((int) *r) / 12 );
379*cdf0e10cSrcweir  } else {
380*cdf0e10cSrcweir	  *r=(double) ( nYear2 - nYear1 );
381*cdf0e10cSrcweir  }
382*cdf0e10cSrcweir}
383*cdf0e10cSrcweir
384*cdf0e10cSrcweir/**
385*cdf0e10cSrcweir * Check if a Date is in a leap year in the Gregorian calendar
386*cdf0e10cSrcweir *
387*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
388*cdf0e10cSrcweir * @param d - date value (in StarCalc representation based 12/30/1899)
389*cdf0e10cSrcweir *
390*cdf0e10cSrcweir */
391*cdf0e10cSrcweirvoid CALLTYPE ScDate_IsLeapYear(double *r, double *d)
392*cdf0e10cSrcweir{
393*cdf0e10cSrcweir  ULONG nDays;
394*cdf0e10cSrcweir  USHORT nDay, nMonth, nYear;
395*cdf0e10cSrcweir  double v=0.0;
396*cdf0e10cSrcweir
397*cdf0e10cSrcweir  if ( d ) v=*d;
398*cdf0e10cSrcweir  nDays=(int) v + nNullDate;
399*cdf0e10cSrcweir
400*cdf0e10cSrcweir  DaysToDate(nDays,&nDay,&nMonth,&nYear);
401*cdf0e10cSrcweir
402*cdf0e10cSrcweir  *r=(double) ( IsLeapYear(nYear) );
403*cdf0e10cSrcweir
404*cdf0e10cSrcweir}
405*cdf0e10cSrcweir
406*cdf0e10cSrcweir/**
407*cdf0e10cSrcweir * Get the Number of Days in the month for a date
408*cdf0e10cSrcweir *
409*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
410*cdf0e10cSrcweir * @param d - date value (in StarCalc representation based 12/30/1899)
411*cdf0e10cSrcweir *
412*cdf0e10cSrcweir */
413*cdf0e10cSrcweirvoid CALLTYPE ScDate_DaysInMonth(double *r, double *d)
414*cdf0e10cSrcweir{
415*cdf0e10cSrcweir  ULONG nDays;
416*cdf0e10cSrcweir  USHORT nDay, nMonth, nYear;
417*cdf0e10cSrcweir  double v=0.0;
418*cdf0e10cSrcweir
419*cdf0e10cSrcweir  if ( d ) v=*d;
420*cdf0e10cSrcweir  nDays=(int) v + nNullDate;
421*cdf0e10cSrcweir
422*cdf0e10cSrcweir  DaysToDate(nDays,&nDay,&nMonth,&nYear);
423*cdf0e10cSrcweir  *r=(double) ( DaysInMonth( nMonth, nYear) );
424*cdf0e10cSrcweir
425*cdf0e10cSrcweir}
426*cdf0e10cSrcweir
427*cdf0e10cSrcweir
428*cdf0e10cSrcweir/**
429*cdf0e10cSrcweir * Get number of weeks in the year for a date
430*cdf0e10cSrcweir *
431*cdf0e10cSrcweir * Most years have 52 weeks, but years that start on a Thursday
432*cdf0e10cSrcweir * and leep years that start on a Wednesday have 53 weeks
433*cdf0e10cSrcweir *
434*cdf0e10cSrcweir * The International Standard IS-8601 has decreed that Monday
435*cdf0e10cSrcweir * shall be the first day of the week.
436*cdf0e10cSrcweir *
437*cdf0e10cSrcweir * A WeekDay can be calculated by substracting 1 and calculating the rest of
438*cdf0e10cSrcweir * a division by 7 from the internal date represention
439*cdf0e10cSrcweir * which gives a 0 - 6 value for Monday - Sunday
440*cdf0e10cSrcweir *
441*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
442*cdf0e10cSrcweir * @param d - date value (in StarCalc represantaion based 30.12.1899)
443*cdf0e10cSrcweir *
444*cdf0e10cSrcweir * @see #IsLeapYear #WeekNumber
445*cdf0e10cSrcweir *
446*cdf0e10cSrcweir */
447*cdf0e10cSrcweirvoid CALLTYPE ScDate_WeeksInYear(double *r, double *d)
448*cdf0e10cSrcweir{
449*cdf0e10cSrcweir  ULONG nDays;
450*cdf0e10cSrcweir  USHORT nDay, nMonth, nYear;
451*cdf0e10cSrcweir  double v=0.0;
452*cdf0e10cSrcweir  long nJan1WeekDay;
453*cdf0e10cSrcweir
454*cdf0e10cSrcweir  if ( d ) v=*d;
455*cdf0e10cSrcweir  nDays=(int) v + nNullDate;
456*cdf0e10cSrcweir
457*cdf0e10cSrcweir  DaysToDate(nDays,&nDay,&nMonth,&nYear);
458*cdf0e10cSrcweir
459*cdf0e10cSrcweir  nJan1WeekDay= ( DateToDays(1,1,nYear) - 1) % 7;
460*cdf0e10cSrcweir
461*cdf0e10cSrcweir  if ( nJan1WeekDay == 3 ) { /* Thursday */
462*cdf0e10cSrcweir	*r=(double) 53;
463*cdf0e10cSrcweir	return;
464*cdf0e10cSrcweir  } else if ( nJan1WeekDay == 2 ) { /* Wednesday */
465*cdf0e10cSrcweir	*r= (double) ( IsLeapYear(nYear) ? 53 : 52 );
466*cdf0e10cSrcweir  } else {
467*cdf0e10cSrcweir	*r= (double) 52;
468*cdf0e10cSrcweir  }
469*cdf0e10cSrcweir}
470*cdf0e10cSrcweir
471*cdf0e10cSrcweir
472*cdf0e10cSrcweir/**
473*cdf0e10cSrcweir * Get number of days in the year of a date specified
474*cdf0e10cSrcweir *
475*cdf0e10cSrcweir * @param *r - return value for the StarCalc function
476*cdf0e10cSrcweir * @param d - date value (in StarCalc represantaion based 30.12.1899)
477*cdf0e10cSrcweir *
478*cdf0e10cSrcweir */
479*cdf0e10cSrcweirvoid CALLTYPE ScDate_DaysInYear(double *r, double *d)
480*cdf0e10cSrcweir{
481*cdf0e10cSrcweir  ULONG nDays;
482*cdf0e10cSrcweir  USHORT nDay, nMonth, nYear;
483*cdf0e10cSrcweir  double v=0.0;
484*cdf0e10cSrcweir
485*cdf0e10cSrcweir  if ( d ) v=*d;
486*cdf0e10cSrcweir  nDays=(int) v + nNullDate;
487*cdf0e10cSrcweir
488*cdf0e10cSrcweir  DaysToDate(nDays,&nDay,&nMonth,&nYear);
489*cdf0e10cSrcweir  *r=(double) ( IsLeapYear(nYear) ? 366 : 365 );
490*cdf0e10cSrcweir
491*cdf0e10cSrcweir}
492*cdf0e10cSrcweir
493*cdf0e10cSrcweir
494*cdf0e10cSrcweir/**
495*cdf0e10cSrcweir * Tell StarCalc how many new functions this Addin provides.
496*cdf0e10cSrcweir *
497*cdf0e10cSrcweir * It's called before any of these new functions is actually
498*cdf0e10cSrcweir * executed and is also used to initialize the NullDate here.
499*cdf0e10cSrcweir *
500*cdf0e10cSrcweir * StarCalc uses a Date Base 12/30/1899
501*cdf0e10cSrcweir * If not specified otherwise in the Options for the Spreedsheet Document
502*cdf0e10cSrcweir *
503*cdf0e10cSrcweir *
504*cdf0e10cSrcweir * @param *nCount - returns the number of functions which are exported to StarCalc
505*cdf0e10cSrcweir *
506*cdf0e10cSrcweir */
507*cdf0e10cSrcweirvoid CALLTYPE GetFunctionCount( USHORT *nCount )
508*cdf0e10cSrcweir{
509*cdf0e10cSrcweir
510*cdf0e10cSrcweir  /* initialize nNullDate Value 0 is 12/30/1899 */
511*cdf0e10cSrcweir  nNullDate=DateToDays(NULLDATE_Day, NULLDATE_Month, NULLDATE_Year);
512*cdf0e10cSrcweir
513*cdf0e10cSrcweir  *nCount = 7;
514*cdf0e10cSrcweir}
515*cdf0e10cSrcweir
516*cdf0e10cSrcweir/**
517*cdf0e10cSrcweir * Provides neccessary data for each new function to StarCalc
518*cdf0e10cSrcweir *
519*cdf0e10cSrcweir * @param *nNo Input: Function number between 0 and nCount - 1
520*cdf0e10cSrcweir * @param *pFuncName Output: Functionname which should be called in the AddIn-DLL
521*cdf0e10cSrcweir * @param *nParamCount Output: Number of Parameter. Must be greater than 0, because there's always a return-Value. Maximum is 16.
522*cdf0e10cSrcweir * @param *peType Output: Pointer to arrray with exactly 16 variables of typ Paramtype. nParamCount Entries are set to the type of the corresponding Parameters.
523*cdf0e10cSrcweir * @param *pInternalName Output: Functionname as seen by the Spreadsheet user
524*cdf0e10cSrcweir *
525*cdf0e10cSrcweir * @see #GetFunctionCount, #GetParameterDescription
526*cdf0e10cSrcweir *
527*cdf0e10cSrcweir */
528*cdf0e10cSrcweirvoid CALLTYPE GetFunctionData( USHORT *    nNo,
529*cdf0e10cSrcweir                               char *      pFuncName,
530*cdf0e10cSrcweir                               USHORT *    nParamCount,
531*cdf0e10cSrcweir                               ParamType * peType,
532*cdf0e10cSrcweir                               char *      pInternalName )
533*cdf0e10cSrcweir{
534*cdf0e10cSrcweir
535*cdf0e10cSrcweir
536*cdf0e10cSrcweir	 switch( *nNo ) {
537*cdf0e10cSrcweir	 case 0:
538*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_WEEK_NAME) );
539*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_GetDiffWeeks" );
540*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
541*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
542*cdf0e10cSrcweir	 peType[2] = PTR_DOUBLE;
543*cdf0e10cSrcweir	 peType[3] = PTR_DOUBLE;
544*cdf0e10cSrcweir	 *nParamCount=4;
545*cdf0e10cSrcweir	 break;
546*cdf0e10cSrcweir
547*cdf0e10cSrcweir	 case 1:
548*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_MONTHS_NAME) );
549*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_GetDiffMonths" );
550*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
551*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
552*cdf0e10cSrcweir	 peType[2] = PTR_DOUBLE;
553*cdf0e10cSrcweir	 peType[3] = PTR_DOUBLE;
554*cdf0e10cSrcweir	 *nParamCount=4;
555*cdf0e10cSrcweir	 break;
556*cdf0e10cSrcweir
557*cdf0e10cSrcweir	 case 2:
558*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_YEARS_NAME) );
559*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_GetDiffYears" );
560*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
561*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
562*cdf0e10cSrcweir	 peType[2] = PTR_DOUBLE;
563*cdf0e10cSrcweir	 peType[3] = PTR_DOUBLE;
564*cdf0e10cSrcweir	 *nParamCount=4;
565*cdf0e10cSrcweir	 break;
566*cdf0e10cSrcweir
567*cdf0e10cSrcweir	 case 3:
568*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_ISLEAPYEAR_NAME) );
569*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_IsLeapYear" );
570*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
571*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
572*cdf0e10cSrcweir	 *nParamCount=2;
573*cdf0e10cSrcweir	 break;
574*cdf0e10cSrcweir
575*cdf0e10cSrcweir	 case 4:
576*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_DAYSINMONTH_NAME) );
577*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_DaysInMonth" );
578*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
579*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
580*cdf0e10cSrcweir	 *nParamCount=2;
581*cdf0e10cSrcweir	 break;
582*cdf0e10cSrcweir
583*cdf0e10cSrcweir	 case 5:
584*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_DAYSINYEAR_NAME) );
585*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_DaysInYear" );
586*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
587*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
588*cdf0e10cSrcweir	 *nParamCount=2;
589*cdf0e10cSrcweir	 break;
590*cdf0e10cSrcweir
591*cdf0e10cSrcweir	 case 6:
592*cdf0e10cSrcweir	 SO_StringCopy( pInternalName, getText(DFA_WEEKSINYEAR_NAME) );
593*cdf0e10cSrcweir	 SO_StringCopy( pFuncName,     "ScDate_WeeksInYear" );
594*cdf0e10cSrcweir	 peType[0] = PTR_DOUBLE;
595*cdf0e10cSrcweir	 peType[1] = PTR_DOUBLE;
596*cdf0e10cSrcweir	 *nParamCount=2;
597*cdf0e10cSrcweir	 break;
598*cdf0e10cSrcweir
599*cdf0e10cSrcweir	 default:
600*cdf0e10cSrcweir            *nParamCount    = 0;
601*cdf0e10cSrcweir            *pFuncName     = 0;
602*cdf0e10cSrcweir            *pInternalName = 0;
603*cdf0e10cSrcweir            break;
604*cdf0e10cSrcweir    }
605*cdf0e10cSrcweir}
606*cdf0e10cSrcweir
607*cdf0e10cSrcweir/**
608*cdf0e10cSrcweir * Provides descriptions for each new function to StarCalc
609*cdf0e10cSrcweir * which are shown is the autopilot
610*cdf0e10cSrcweir *
611*cdf0e10cSrcweir * @param *nNo Input Parameter, Function number between 0 and nCount - 1
612*cdf0e10cSrcweir * @param *nParam Parameter Number
613*cdf0e10cSrcweir * @param *pName Output: Name of the parameter
614*cdf0e10cSrcweir * @param *pDesc Output: Description of the parameter
615*cdf0e10cSrcweir *
616*cdf0e10cSrcweir * @see #GetFunctionCount, #GetParameterDescription
617*cdf0e10cSrcweir */
618*cdf0e10cSrcweirvoid CALLTYPE GetParameterDescription( USHORT* nNo, USHORT* nParam,
619*cdf0e10cSrcweirchar* pName, char* pDesc )
620*cdf0e10cSrcweir{
621*cdf0e10cSrcweir	*pName = 0;
622*cdf0e10cSrcweir	*pDesc = 0;
623*cdf0e10cSrcweir
624*cdf0e10cSrcweir	switch ( *nNo ) {
625*cdf0e10cSrcweir	case 0:	/* Weeks */
626*cdf0e10cSrcweir		switch ( *nParam ) {
627*cdf0e10cSrcweir		case 0:
628*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_WEEK_DESC));
629*cdf0e10cSrcweir			break;
630*cdf0e10cSrcweir		case 1:
631*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
632*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_WEEK_PAR1_DESC));
633*cdf0e10cSrcweir			break;
634*cdf0e10cSrcweir		case 2:
635*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
636*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_WEEK_PAR2_DESC));
637*cdf0e10cSrcweir			break;
638*cdf0e10cSrcweir		case 3:
639*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
640*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_WEEK_PAR3_DESC));
641*cdf0e10cSrcweir			break;
642*cdf0e10cSrcweir		}
643*cdf0e10cSrcweir		break;
644*cdf0e10cSrcweir	case 1: /* Months */
645*cdf0e10cSrcweir		switch ( *nParam ) {
646*cdf0e10cSrcweir		case 0:
647*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_MONTHS_DESC));
648*cdf0e10cSrcweir			break;
649*cdf0e10cSrcweir		case 1:
650*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
651*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR1_DESC));
652*cdf0e10cSrcweir			break;
653*cdf0e10cSrcweir		case 2:
654*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
655*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR2_DESC));
656*cdf0e10cSrcweir			break;
657*cdf0e10cSrcweir		case 3:
658*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
659*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR3_DESC));
660*cdf0e10cSrcweir			break;
661*cdf0e10cSrcweir		}
662*cdf0e10cSrcweir		break;
663*cdf0e10cSrcweir	case 2: /* Years */
664*cdf0e10cSrcweir		switch ( *nParam ) {
665*cdf0e10cSrcweir		case 0:
666*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_YEARS_DESC));
667*cdf0e10cSrcweir			break;
668*cdf0e10cSrcweir		case 1:
669*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
670*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_YEARS_PAR1_DESC));
671*cdf0e10cSrcweir			break;
672*cdf0e10cSrcweir		case 2:
673*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
674*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_YEARS_PAR2_DESC));
675*cdf0e10cSrcweir			break;
676*cdf0e10cSrcweir		case 3:
677*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
678*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_YEARS_PAR3_DESC));
679*cdf0e10cSrcweir			break;
680*cdf0e10cSrcweir		}
681*cdf0e10cSrcweir	   break;
682*cdf0e10cSrcweir	case 3:	/* IsLeapYear */
683*cdf0e10cSrcweir		switch ( *nParam ) {
684*cdf0e10cSrcweir		case 0:
685*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_ISLEAPYEAR_DESC));
686*cdf0e10cSrcweir			break;
687*cdf0e10cSrcweir		case 1:
688*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
689*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
690*cdf0e10cSrcweir			break;
691*cdf0e10cSrcweir		}
692*cdf0e10cSrcweir		break;
693*cdf0e10cSrcweir	case 4:	/* DaysInMonth */
694*cdf0e10cSrcweir		switch ( *nParam ) {
695*cdf0e10cSrcweir		case 0:
696*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_DAYSINMONTH_DESC));
697*cdf0e10cSrcweir			break;
698*cdf0e10cSrcweir		case 1:
699*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
700*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
701*cdf0e10cSrcweir			break;
702*cdf0e10cSrcweir		}
703*cdf0e10cSrcweir		break;
704*cdf0e10cSrcweir	case 5:	/* DaysInYear */
705*cdf0e10cSrcweir		switch ( *nParam ) {
706*cdf0e10cSrcweir		case 0:
707*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_DAYSINYEAR_DESC));
708*cdf0e10cSrcweir			break;
709*cdf0e10cSrcweir		case 1:
710*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
711*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
712*cdf0e10cSrcweir			break;
713*cdf0e10cSrcweir		}
714*cdf0e10cSrcweir		break;
715*cdf0e10cSrcweir
716*cdf0e10cSrcweir	case 6:	/* WeeksInYear */
717*cdf0e10cSrcweir		switch ( *nParam ) {
718*cdf0e10cSrcweir		case 0:
719*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_WEEKSINYEAR_DESC));
720*cdf0e10cSrcweir			break;
721*cdf0e10cSrcweir		case 1:
722*cdf0e10cSrcweir			SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
723*cdf0e10cSrcweir			SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
724*cdf0e10cSrcweir			break;
725*cdf0e10cSrcweir		}
726*cdf0e10cSrcweir		break;
727*cdf0e10cSrcweir	}
728*cdf0e10cSrcweir
729*cdf0e10cSrcweir}
730