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