merge the formfield patch from ooo-build
[ooovba.git] / sc / addin / datefunc / dfa.cl
blob2a2c0142222b872cc881875d4d027f47113bc5f3
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dfa.cl,v $
10 * $Revision: 1.4 $
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."; */
33 #include <string.h>
34 #include <stdlib.h>
35 #include <math.h>
37 #include <xlang.h>
38 #include <addin.h>
39 #include <dfa.hrc>
42 /**
43 * the current language the Addin is using
45 static USHORT _nLanguage=LANGUAGE_ENGLISH;
47 /**
48 * StarCalc calls this function to set a new current Language for the Addin
50 * @param *nLanguage
53 void CALLTYPE SetLanguage( USHORT* nLanguage )
55 _nLanguage = GetNeutralLanguage( *nLanguage );
59 /**
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
83 /**
84 * Array holding values for month length, used in DaysInMonth() function
86 * @see #DaysInMonth
89 static USHORT aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
90 31, 31, 30, 31, 30, 31 };
92 /**
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 )
118 if ( nMonth != 2 )
119 return aDaysInMonth[nMonth-1];
120 else
122 if ( IsLeapYear(nYear) )
123 return aDaysInMonth[nMonth-1] + 1;
124 else
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 )
146 long nDays;
147 USHORT i;
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);
154 nDays += nDay;
156 return nDays;
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 )
177 long nTempDays;
178 long i = 0;
179 BOOL bCalc;
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);
187 bCalc = FALSE;
188 if ( nTempDays < 1 )
190 i++;
191 bCalc = TRUE;
193 else
195 if ( nTempDays > 365 )
197 if ( (nTempDays != 366) || !IsLeapYear( *pYear ) )
199 i--;
200 bCalc = TRUE;
205 while ( bCalc );
207 *pMonth = 1;
208 while ( (ULONG)nTempDays > DaysInMonth( *pMonth, *pYear ) )
210 nTempDays -= DaysInMonth( *pMonth, *pYear );
211 (*pMonth)++;
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)
274 long nDays1=0;
275 long nDays2=0;
276 int nMode=0;
278 if ( d1 ) nDays1=(long)floor(*d1)+nNullDate;
279 if ( d2 ) nDays2=(long)floor(*d2)+nNullDate;
282 if ( dMode) nMode=(int)*dMode;
284 if ( nMode == 1 ) {
286 USHORT nDay,nMonth,nYear;
287 long nJan4;
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 ) );
294 } else {
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;
321 long nDays1=0;
322 long nDays2=0;
323 int nMode=0;
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 ) {
338 *r -= 1;
340 } else {
341 if ( nDay1 < nDay2 ) {
342 *r += 1;
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;
368 long nDays1=0;
369 long nDays2=0;
370 int nMode=0;
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);
379 if ( nMode != 1 ) {
380 ScDate_GetDiffMonths(r,d1,d2,dMode);
381 *r= (double) ( ((int) *r) / 12 );
382 } else {
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)
396 ULONG nDays;
397 USHORT nDay, nMonth, nYear;
398 double v=0.0;
400 if ( d ) v=*d;
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)
418 ULONG nDays;
419 USHORT nDay, nMonth, nYear;
420 double v=0.0;
422 if ( d ) v=*d;
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)
452 ULONG nDays;
453 USHORT nDay, nMonth, nYear;
454 double v=0.0;
455 long nJan1WeekDay;
457 if ( d ) v=*d;
458 nDays=(int) v + nNullDate;
460 DaysToDate(nDays,&nDay,&nMonth,&nYear);
462 nJan1WeekDay= ( DateToDays(1,1,nYear) - 1) % 7;
464 if ( nJan1WeekDay == 3 ) { /* Thursday */
465 *r=(double) 53;
466 return;
467 } else if ( nJan1WeekDay == 2 ) { /* Wednesday */
468 *r= (double) ( IsLeapYear(nYear) ? 53 : 52 );
469 } else {
470 *r= (double) 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)
484 ULONG nDays;
485 USHORT nDay, nMonth, nYear;
486 double v=0.0;
488 if ( d ) v=*d;
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);
516 *nCount = 7;
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,
532 char * pFuncName,
533 USHORT * nParamCount,
534 ParamType * peType,
535 char * pInternalName )
539 switch( *nNo ) {
540 case 0:
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;
547 *nParamCount=4;
548 break;
550 case 1:
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;
557 *nParamCount=4;
558 break;
560 case 2:
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;
567 *nParamCount=4;
568 break;
570 case 3:
571 SO_StringCopy( pInternalName, getText(DFA_ISLEAPYEAR_NAME) );
572 SO_StringCopy( pFuncName, "ScDate_IsLeapYear" );
573 peType[0] = PTR_DOUBLE;
574 peType[1] = PTR_DOUBLE;
575 *nParamCount=2;
576 break;
578 case 4:
579 SO_StringCopy( pInternalName, getText(DFA_DAYSINMONTH_NAME) );
580 SO_StringCopy( pFuncName, "ScDate_DaysInMonth" );
581 peType[0] = PTR_DOUBLE;
582 peType[1] = PTR_DOUBLE;
583 *nParamCount=2;
584 break;
586 case 5:
587 SO_StringCopy( pInternalName, getText(DFA_DAYSINYEAR_NAME) );
588 SO_StringCopy( pFuncName, "ScDate_DaysInYear" );
589 peType[0] = PTR_DOUBLE;
590 peType[1] = PTR_DOUBLE;
591 *nParamCount=2;
592 break;
594 case 6:
595 SO_StringCopy( pInternalName, getText(DFA_WEEKSINYEAR_NAME) );
596 SO_StringCopy( pFuncName, "ScDate_WeeksInYear" );
597 peType[0] = PTR_DOUBLE;
598 peType[1] = PTR_DOUBLE;
599 *nParamCount=2;
600 break;
602 default:
603 *nParamCount = 0;
604 *pFuncName = 0;
605 *pInternalName = 0;
606 break;
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 )
624 *pName = 0;
625 *pDesc = 0;
627 switch ( *nNo ) {
628 case 0: /* Weeks */
629 switch ( *nParam ) {
630 case 0:
631 SO_StringCopy(pDesc,getText(DFA_WEEK_DESC));
632 break;
633 case 1:
634 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
635 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR1_DESC));
636 break;
637 case 2:
638 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
639 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR2_DESC));
640 break;
641 case 3:
642 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
643 SO_StringCopy(pDesc,getText(DFA_WEEK_PAR3_DESC));
644 break;
646 break;
647 case 1: /* Months */
648 switch ( *nParam ) {
649 case 0:
650 SO_StringCopy(pDesc,getText(DFA_MONTHS_DESC));
651 break;
652 case 1:
653 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
654 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR1_DESC));
655 break;
656 case 2:
657 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
658 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR2_DESC));
659 break;
660 case 3:
661 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
662 SO_StringCopy(pDesc,getText(DFA_MONTHS_PAR3_DESC));
663 break;
665 break;
666 case 2: /* Years */
667 switch ( *nParam ) {
668 case 0:
669 SO_StringCopy(pDesc,getText(DFA_YEARS_DESC));
670 break;
671 case 1:
672 SO_StringCopy(pName,getText(DFA_PAR_DATE1_NAME));
673 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR1_DESC));
674 break;
675 case 2:
676 SO_StringCopy(pName,getText(DFA_PAR_DATE2_NAME));
677 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR2_DESC));
678 break;
679 case 3:
680 SO_StringCopy(pName,getText(DFA_PAR_MODE_NAME));
681 SO_StringCopy(pDesc,getText(DFA_YEARS_PAR3_DESC));
682 break;
684 break;
685 case 3: /* IsLeapYear */
686 switch ( *nParam ) {
687 case 0:
688 SO_StringCopy(pDesc,getText(DFA_ISLEAPYEAR_DESC));
689 break;
690 case 1:
691 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
692 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
693 break;
695 break;
696 case 4: /* DaysInMonth */
697 switch ( *nParam ) {
698 case 0:
699 SO_StringCopy(pDesc,getText(DFA_DAYSINMONTH_DESC));
700 break;
701 case 1:
702 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
703 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
704 break;
706 break;
707 case 5: /* DaysInYear */
708 switch ( *nParam ) {
709 case 0:
710 SO_StringCopy(pDesc,getText(DFA_DAYSINYEAR_DESC));
711 break;
712 case 1:
713 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
714 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
715 break;
717 break;
719 case 6: /* WeeksInYear */
720 switch ( *nParam ) {
721 case 0:
722 SO_StringCopy(pDesc,getText(DFA_WEEKSINYEAR_DESC));
723 break;
724 case 1:
725 SO_StringCopy(pName,getText(DFA_PAR_DATE_NAME));
726 SO_StringCopy(pDesc,getText(DFA_PAR_DATE_DESC)); /* StarCalc Value */
727 break;
729 break;