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