1d4a3fa4bSAndrew Rist/************************************************************** 2cdf0e10cSrcweir * 3d4a3fa4bSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4d4a3fa4bSAndrew Rist * or more contributor license agreements. See the NOTICE file 5d4a3fa4bSAndrew Rist * distributed with this work for additional information 6d4a3fa4bSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7d4a3fa4bSAndrew Rist * to you under the Apache License, Version 2.0 (the 8d4a3fa4bSAndrew Rist * "License"); you may not use this file except in compliance 9d4a3fa4bSAndrew Rist * with the License. You may obtain a copy of the License at 10d4a3fa4bSAndrew Rist * 11d4a3fa4bSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12d4a3fa4bSAndrew Rist * 13d4a3fa4bSAndrew Rist * Unless required by applicable law or agreed to in writing, 14d4a3fa4bSAndrew Rist * software distributed under the License is distributed on an 15d4a3fa4bSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16d4a3fa4bSAndrew Rist * KIND, either express or implied. See the License for the 17d4a3fa4bSAndrew Rist * specific language governing permissions and limitations 18d4a3fa4bSAndrew Rist * under the License. 19d4a3fa4bSAndrew Rist * 20d4a3fa4bSAndrew 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 54*4200b705SJohn Bampton * If not specified otherwise in the Settings for the Spreadsheet Document. 55cdf0e10cSrcweir * 56*4200b705SJohn Bampton * There's no way to get the Spreadsheet settings from within 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 * 22086e1cf34SPedro Giffuni * A week that lies partly in one year and partly in another 221fb0b81f5Smseidel * is assigned a number in 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 * 22786e1cf34SPedro Giffuni * A WeekDay can be then calculated by subtracting 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 * 23786e1cf34SPedro Giffuni * If a day in the same or another 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 * 43186e1cf34SPedro Giffuni * A WeekDay can be calculated by subtracting 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 495*4200b705SJohn Bampton * If not specified otherwise in the Options for the Spreadsheet 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/** 51186e1cf34SPedro Giffuni * Provides necessary 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