1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright
2008 by Sun Microsystems
, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software
: you can redistribute it and
/or modify
15 * it under the terms of the GNU Lesser General Public License version
3
16 * only
, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful
,
19 * but WITHOUT ANY WARRANTY
; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version
3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code
).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version
3 along with OpenOffice.org. If not
, see
26 * <http
://www.openoffice.org
/license.html
>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 /* static char datefunc_Id
[]="@(#) StarCalc Datefunc AddIn (c) 1998-2000 Sun Microsystems, Inc."; */
43 * the current language the Addin is using
45 static USHORT _nLanguage
=LANGUAGE_ENGLISH
;
48 * StarCalc calls this function to set a new current Language for the Addin
53 void CALLTYPE SetLanguage
( USHORT
* nLanguage
)
55 _nLanguage
= GetNeutralLanguage
( *nLanguage
);
60 * Null Date
, initialized in GetFunctionCount
62 * StarCalc uses a BaseDate
12/30/1899
63 * If not specified otherwise in the Settings for the Spreedsheet Document.
65 * There
's no way to get the Spreadsheet settings from whithin a simple addin
,
66 * so this Addin can only be used by documents using the default BaseDate setting.
68 * The functions in this Addin use a BaseDate
01/01/0001
69 * The nNullDate Variable is the StarCalc BaseDate converted to
70 * this internal date representation.
72 * @see
#GetFunctionCount
76 static ULONG nNullDate
=0;
78 #define NULLDATE_Year
1899
79 #define NULLDATE_Month
12
80 #define NULLDATE_Day
30
84 * Array holding values for month length
, used in DaysInMonth
() function
89 static USHORT aDaysInMonth
[12] = { 31, 28, 31, 30, 31, 30,
90 31, 31, 30, 31, 30, 31 };
93 * Check if a year is a leap year in the Gregorian calendar
95 * @param nYear the year which should be checked
96 * @return true if the year is a leap year, false otherwise.
98 * @see #DaysInMonth, #IsLeapYear,
99 * @see #ScDate_DaysInMonth, #ScDate_IsLeapYear, #ScDate_WeeksInYear
102 static BOOL IsLeapYear( USHORT nYear )
104 return (BOOL)((((nYear % 4) == 0) && ((nYear % 100) != 0)) || ((nYear % 400) == 0));
109 * Get the number of days in a specified month
111 * @param nMonth the number of the Month
112 * @param nYear the year
113 * @return number of days
116 static USHORT DaysInMonth( USHORT nMonth, USHORT nYear )
119 return aDaysInMonth[nMonth-1];
122 if ( IsLeapYear(nYear) )
123 return aDaysInMonth[nMonth-1] + 1;
125 return aDaysInMonth[nMonth-1];
131 * Convert a date to a count of days starting from 01/01/0001
133 * The internal representation of a Date used in this Addin
134 * is the number of days between 01/01/0001 and the date
135 * this function converts a Day , Month, Year representation
136 * to this internal Date value.
138 * @param nDay the day of the Month
139 * @param nMonth the number of the Month
140 * @param nYear the Year
141 * @return count of days from 01/01/0001 to the date specified
144 static long DateToDays( USHORT nDay, USHORT nMonth, USHORT nYear )
149 nDays = ((ULONG)nYear-1) * 365;
150 nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
152 for( i = 1; i < nMonth; i++ )
153 nDays += DaysInMonth(i,nYear);
161 * Convert a count of days starting from 01/01/0001 to a date
163 * The internal representation of a Date used in this Addin
164 * is the number of days between 01/01/0001 and the date
165 * this function converts this internal Date value
166 * to a Day , Month, Year representation of a Date.
168 * @param nDay count of days from 01/01/0001
169 * @param *pDay pointer to a variable for the day of the month
170 * @param *pMonth pointer to a variable for the month
171 * @param *pYear pointer to a variable for the year
174 static void DaysToDate( long nDays,
175 USHORT *pDay, USHORT *pMonth, USHORT *pYear )
183 nTempDays = (long)nDays;
184 *pYear = (USHORT)((nTempDays / 365) - i);
185 nTempDays -= ((ULONG) *pYear -1) * 365;
186 nTempDays -= (( *pYear -1) / 4) - (( *pYear -1) / 100) + ((*pYear -1) / 400);
195 if ( nTempDays > 365 )
197 if ( (nTempDays != 366) || !IsLeapYear( *pYear ) )
208 while ( (ULONG)nTempDays > DaysInMonth( *pMonth, *pYear ) )
210 nTempDays -= DaysInMonth( *pMonth, *pYear );
213 *pDay = (USHORT)nTempDays;
217 * Get week difference between 2 dates
219 * new Weeks(date1,date2,mode) function for StarCalc
221 * Two modes of operation are provided.
222 * The first is just a simple division by 7 calculation.
224 * The second calculates the diffence by week of year.
226 * The International Standard IS-8601 has decreed that Monday
227 * shall be the first day of the week.
229 * A week that lies partly in one year and partly in annother
230 * is assigned a number in the the year in which most of its days lie.
232 * That means that week 1 of any year is the week that contains the 4. January
234 * The internal representation of a Date used in the Addin is the number of days based on 01/01/0001
236 * A WeekDay can be then calculated by substracting 1 and calculating the rest of
237 * a division by 7, which gives a 0 - 6 value for Monday - Sunday
239 * Using the 4. January rule explained above the formula
241 * nWeek1= ( nDays1 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
243 * calculates a number between 0-53 for each day which is in the same year as nJan4
244 * where 0 means that this week belonged to the year before.
246 * If a day in the same or annother year is used in this formula this calculates
247 * an calendar week offset from a given 4. January
249 * nWeek2 = ( nDays2 - nJan4 + ( (nJan4-1) % 7 ) ) / 7 + 1;
251 * The 4.January of first Date Argument can thus be used to calculate
252 * the week difference by calendar weeks which is then nWeek = nWeek2 - nWeek1
254 * which can be optimized to
256 * nWeek = ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 )
258 * Note: All calculations are operating on the long integer data type
259 * % is the modulo operator in C which calculates the rest of an Integer division
262 * @param *r - return value for the StarCalc function
263 * @param d1 - date value (in StarCalc representation based 12/30/1899), usually the older date
264 * @param d2 - date value (in StarCalc representation based 12/30/1899), usually the younger date
265 * @param dMode - mode of operation
267 * mode 0 is the interval between the dates in month, that is days / 7
269 * mode 1 is the difference by week of year
272 void CALLTYPE ScDate_GetDiffWeeks(double *r, double *d1, double *d2, double *dMode)
278 if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
279 if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
282 if ( dMode) nMode=(int)*dMode;
286 USHORT nDay,nMonth,nYear;
289 DaysToDate(nDays1,&nDay,&nMonth,&nYear);
290 nJan4=DateToDays(4,1,nYear);
292 *r=(double) ( ( (nDays2-nJan4+((nJan4-1)%7))/7 ) - ( (nDays1-nJan4+((nJan4-1)%7))/7 ) );
296 *r= (double) ( (nDays2 - nDays1) / 7 ) ;
302 * Get month difference between 2 dates
303 * =Month(start, end, mode) Function for StarCalc
305 * two modes are provided
307 * @param *r - return value for the StarCalc function
308 * @param d1 - date value, start date
309 * @param d2 - date value, end date
310 * @param dMode - mode of operation
312 * mode 0 is the interval between the dates in month
314 * mode 1 is the difference in calendar month
317 void CALLTYPE ScDate_GetDiffMonths(double *r, double *d1, double *d2, double *dMode)
319 USHORT nDay1,nMonth1,nYear1;
320 USHORT nDay2,nMonth2,nYear2;
325 if ( dMode) nMode=(int)*dMode;
327 if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
328 if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
330 DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
331 DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
333 *r=(double) ( nMonth2 - nMonth1 + (nYear2 - nYear1) * 12 );
334 if ( nMode == 1 || nDays1 == nDays2 ) return;
336 if ( nDays1 < nDays2 ) {
337 if ( nDay1 > nDay2 ) {
341 if ( nDay1 < nDay2 ) {
350 * Get Year difference between 2 dates
352 * two modes are provided
354 * @param *r - return value for the StarCalc function
355 * @param d1 - date value, start date
356 * @param d2 - date value, end date
357 * @param dMode - mode of operation
359 * mode 0 is the interval between the dates in years
361 * mode 1 is the difference in calendar years
364 void CALLTYPE ScDate_GetDiffYears(double *r, double *d1, double *d2, double *dMode)
366 USHORT nDay1,nMonth1,nYear1;
367 USHORT nDay2,nMonth2,nYear2;
372 if ( dMode) nMode=(int)*dMode;
374 if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
375 if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
377 DaysToDate(nDays1,&nDay1,&nMonth1,&nYear1);
378 DaysToDate(nDays2,&nDay2,&nMonth2,&nYear2);
380 ScDate_GetDiffMonths(r,d1,d2,dMode);
381 *r= (double) ( ((int) *r) / 12 );
383 *r=(double) ( nYear2 - nYear1 );
388 * Check if a Date is in a leap year in the Gregorian calendar
390 * @param *r - return value for the StarCalc function
391 * @param d - date value (in StarCalc representation based 12/30/1899)
394 void CALLTYPE ScDate_IsLeapYear(double *r, double *d)
397 USHORT nDay, nMonth, nYear;
401 nDays=(int) v + nNullDate;
403 DaysToDate(nDays,&nDay,&nMonth,&nYear);
405 *r=(double) ( IsLeapYear(nYear) );
410 * Get the Number of Days in the month for a date
412 * @param *r - return value for the StarCalc function
413 * @param d - date value (in StarCalc representation based 12/30/1899)
416 void CALLTYPE ScDate_DaysInMonth(double *r, double *d)
419 USHORT nDay, nMonth, nYear;
423 nDays=(int) v + nNullDate;
425 DaysToDate(nDays,&nDay,&nMonth,&nYear);
426 *r=(double) ( DaysInMonth( nMonth, nYear) );
432 * Get number of weeks in the year for a date
434 * Most years have 52 weeks, but years that start on a Thursday
435 * and leep years that start on a Wednesday have 53 weeks
437 * The International Standard IS-8601 has decreed that Monday
438 * shall be the first day of the week.
440 * A WeekDay can be calculated by substracting 1 and calculating the rest of
441 * a division by 7 from the internal date represention
442 * which gives a 0 - 6 value for Monday - Sunday
444 * @param *r - return value for the StarCalc function
445 * @param d - date value (in StarCalc represantaion based 30.12.1899)
447 * @see #IsLeapYear #WeekNumber
450 void CALLTYPE ScDate_WeeksInYear(double *r, double *d)
453 USHORT nDay, nMonth, nYear;
458 nDays=(int) v + nNullDate;
460 DaysToDate(nDays,&nDay,&nMonth,&nYear);
462 nJan1WeekDay= ( DateToDays(1,1,nYear) - 1) % 7;
464 if ( nJan1WeekDay == 3 ) { /* Thursday */
467 } else if ( nJan1WeekDay == 2 ) { /* Wednesday */
468 *r= (double) ( IsLeapYear(nYear) ? 53 : 52 );
476 * Get number of days in the year of a date specified
478 * @param *r - return value for the StarCalc function
479 * @param d - date value (in StarCalc represantaion based 30.12.1899)
482 void CALLTYPE ScDate_DaysInYear(double *r, double *d)
485 USHORT nDay, nMonth, nYear;
489 nDays=(int) v + nNullDate;
491 DaysToDate(nDays,&nDay,&nMonth,&nYear);
492 *r=(double) ( IsLeapYear(nYear) ? 366 : 365 );
498 * Tell StarCalc how many new functions this Addin provides.
500 * It's called before any of these new functions is actually
501 * executed and is also used to initialize the NullDate here.
503 * StarCalc uses a Date Base 12/30/1899
504 * If not specified otherwise in the Options for the Spreedsheet Document
507 * @param *nCount - returns the number of functions which are exported to StarCalc
510 void CALLTYPE GetFunctionCount( USHORT *nCount )
513 /* initialize nNullDate Value 0 is 12/30/1899 */
514 nNullDate=DateToDays(NULLDATE_Day, NULLDATE_Month, NULLDATE_Year);
520 * Provides neccessary data for each new function to StarCalc
522 * @param *nNo Input: Function number between 0 and nCount - 1
523 * @param *pFuncName Output: Functionname which should be called in the AddIn-DLL
524 * @param *nParamCount Output: Number of Parameter. Must be greater than 0, because there's always a return-Value. Maximum is 16.
525 * @param *peType Output: Pointer to arrray with exactly 16 variables of typ Paramtype. nParamCount Entries are set to the type of the corresponding Parameters.
526 * @param *pInternalName Output: Functionname as seen by the Spreadsheet user
528 * @see #GetFunctionCount, #GetParameterDescription
531 void CALLTYPE GetFunctionData( USHORT * nNo,
533 USHORT * nParamCount,
535 char * pInternalName )
541 SO_StringCopy( pInternalName, getText(DFA_WEEK_NAME) );
542 SO_StringCopy( pFuncName, "ScDate_GetDiffWeeks" );
543 peType[0] = PTR_DOUBLE;
544 peType[1] = PTR_DOUBLE;
545 peType[2] = PTR_DOUBLE;
546 peType[3] = PTR_DOUBLE;
551 SO_StringCopy( pInternalName, getText(DFA_MONTHS_NAME) );
552 SO_StringCopy( pFuncName, "ScDate_GetDiffMonths" );
553 peType[0] = PTR_DOUBLE;
554 peType[1] = PTR_DOUBLE;
555 peType[2] = PTR_DOUBLE;
556 peType[3] = PTR_DOUBLE;
561 SO_StringCopy( pInternalName, getText(DFA_YEARS_NAME) );
562 SO_StringCopy( pFuncName, "ScDate_GetDiffYears" );
563 peType[0] = PTR_DOUBLE;
564 peType[1] = PTR_DOUBLE;
565 peType[2] = PTR_DOUBLE;
566 peType[3] = PTR_DOUBLE;
571 SO_StringCopy( pInternalName, getText(DFA_ISLEAPYEAR_NAME) );
572 SO_StringCopy( pFuncName, "ScDate_IsLeapYear" );
573 peType[0] = PTR_DOUBLE;
574 peType[1] = PTR_DOUBLE;
579 SO_StringCopy( pInternalName, getText(DFA_DAYSINMONTH_NAME) );
580 SO_StringCopy( pFuncName, "ScDate_DaysInMonth" );
581 peType[0] = PTR_DOUBLE;
582 peType[1] = PTR_DOUBLE;
587 SO_StringCopy( pInternalName, getText(DFA_DAYSINYEAR_NAME) );
588 SO_StringCopy( pFuncName, "ScDate_DaysInYear" );
589 peType[0] = PTR_DOUBLE;
590 peType[1] = PTR_DOUBLE;
595 SO_StringCopy( pInternalName, getText(DFA_WEEKSINYEAR_NAME) );
596 SO_StringCopy( pFuncName, "ScDate_WeeksInYear" );
597 peType[0] = PTR_DOUBLE;
598 peType[1] = PTR_DOUBLE;
611 * Provides descriptions for each new function to StarCalc
612 * which are shown is the autopilot
614 * @param *nNo Input Parameter, Function number between 0 and nCount - 1
615 * @param *nParam Parameter Number
616 * @param *pName Output: Name of the parameter
617 * @param *pDesc Output: Description of the parameter
619 * @see #GetFunctionCount, #GetParameterDescription
621 void CALLTYPE GetParameterDescription( USHORT* nNo, USHORT* nParam,
622 char* pName, char* pDesc )
631 SO_StringCopy(pDesc,getText(DFA_WEEK_DESC));
634 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
635 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR1_DESC));
638 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
639 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR2_DESC));
642 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
643 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR3_DESC));
650 SO_StringCopy(pDesc,getText(DFA_MONTHS_DESC));
653 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
654 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR1_DESC));
657 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
658 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR2_DESC));
661 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
662 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR3_DESC));
669 SO_StringCopy(pDesc,getText(DFA_YEARS_DESC));
672 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
673 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR1_DESC));
676 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
677 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR2_DESC));
680 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
681 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR3_DESC));
685 case 3: /* IsLeapYear */
688 SO_StringCopy(pDesc,getText(DFA_ISLEAPYEAR_DESC));
691 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
692 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
696 case 4: /* DaysInMonth */
699 SO_StringCopy(pDesc,getText(DFA_DAYSINMONTH_DESC));
702 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
703 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
707 case 5: /* DaysInYear */
710 SO_StringCopy(pDesc,getText(DFA_DAYSINYEAR_DESC));
713 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
714 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
719 case 6: /* WeeksInYear */
722 SO_StringCopy(pDesc,getText(DFA_WEEKSINYEAR_DESC));
725 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
726 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */