by Dr. Peter Wayne
| Let's come up with a few new date functions for Alpha Five. After you read the article, see if you can solve the puzzler at the end! |
Alpha Five comes with a comprehensive set of functions, but no matter how many functions are supplied, there is always a need for one more. Well, with Alpha Five's User Defined Functions, or UDFs, you're not limited to the functions that Alpha's development team included: you can write your own.
Let's add a few useful general-purpose date functions. Perhaps the most glaring omission in the Alpha Five function list is an isDate() function, to verify whether a given string equates to a valid date. If you haven't written a function before, then isDate() would be a good place to start.
From the Code tab of the Control Panel, choose New, and then choose Function:
Figure 1. Create New Object dialog.
After you click on Finish, you enter the function type and the function parameters or arguments. This function will return .t. or .f., so it will be of type logical. It will accept a single argument of type character. Here is the function prototyping screen:

Figure 2. The function is of type logical with an input of type
character.
The code for the function is quite simple, and relies on the eval_valid() function that was added to Alpha Five version 3.04:
function isDate as L(datestr as C)
' type your code here
isDate=eval_valid("{"+datestr+"}")
end function
Script 1. The isDate() function.
The function can be invoked from the interactive window quite easily:
? isDate("2/29/98")
= .F.
? isDate("2/31/2000")
= .F.
? isDate(dtoc(date()))
= .T.
? isDate("2/29/2000")
= .T.
Figure 3. Examples of using the isDate() function.
isLeapYear() is nother useful function we can write. It takes any year and tells us if it is a leap year or not. A year is a leap year if it
Thus 1900 is not a leap year but 2000 is. We can use the modulus or mod() fuction to translate the phrase, "is evenly divisible by." Here, then, is the Xbasic code for the isLeapYear() function:
function isLeapYear as L(yr as N) select case mod(yr,4)>0 isLeapYear=.f. case mod(yr,400)=0 isLeapYear=.t. case mod(yr,100)=0 isLeapYear=.f. case else isLeapYear=.t. end select end function
Script 2:isLeapYear()
Note that this script takes advantage of the fact that a select..case
construction only evaluates the first true case statement. By
putting the test for mod(yr,400 before the test for
mod(yr,100) I can guarantee that the year 2000 will only be
evaluated in the first test. This point is so important that I'll repeat
it: the order of the case statements in a
select..case construction determines the order of evaluation and may have
profound effects on the results.
Let's try a few years:
? isLeapYear(2000) = .T. ?isLeapYear(1900) = .F. ?isLeapYear(1996) = .T. ?isLeapYear(1998) = .F.
Figure 4. Use of isLeapYear()
Two other useful functions are isWeekendDay() and isWeekDay() which tell whether a given date falls on a weekend or not:
function isWeekendDay as L(anyday as D) isWeekendDay=dow(anyday)=1 .or. dow(anyday)=7 end function |
? isWeekendDay({9/27/98})
= .T.
? isWeekendDay({9/28/98})
= .F. |
The isWeekDay() function is equally straightforward:
function isWeekDay as L(anyday as D) isWeekday=anyday>1 .and. anyday<7 end function
Script 4. isWeekDay()
Let's come up with a slightly more complex example. Let's say you need to know the end of the month for a given date. Sometimes the last day of the month will be the 28th, sometimes the 29th, sometimes the 30th, and most often the 31st. The EndOfMonth() function takes a date as its input and returns another date as its output. It calls on the isLeapYear() function we defined earlier:
function EndOfMonth as D(anyday as D) dim m as n dim y as n dim d as n m=month(anyday) y=year(anyday) select case m=2 if isLeapYear(y) then d=29 else d=28 end if case m=4 .or. m=6 .or. m=9 .or. m=11 d=30 case else d=31 end select EndOfMonth=ctod(ltrim(str(m))+"/"+ltrim(str(d))+"/"+ltrim(str(y))) end function
Script 4. EndOfMonth()
And we can test the function:
? EndOfMonth({2/1/2000})
= {02/29/2000}
? EndOfMonth({9/15/98})
= {09/30/1998}
? EndOfMonth({2/1/98})
= {02/28/1998}
? EndOfMonth({10/2/98})
= {10/31/1998}
Figure 5. Use of EndOfMonth() function.
| Entry Rules for the Date Puzzler: Fine Print Employees of Alpha Software or Softquad International are not ineligible to enter. Employees of General Mills and their family members, dependents, friends and associates, or any residents of Battle Creek, Michigan, are only allowed to enter after special dispensation from Kenneth Starr and the House Ethics Committee. Agents of foreign governments may enter the contest if they can prove contributions to either the Republican or Democratic National Committee in any of the last 4 Presidential electoral campaigns. Bribery of lesser officials, such as Congressmen, State Senators, Mayors or Governors is not sufficient. Plagiarism will be swiftly punished but cooperative problem-solving is encouraged. |
Now, here comes the puzzle for the week.
The New York area Alpha Users Group meets on the second Wednesday of every month, except in August, when it does not meet at all. I'm always forgetting the date of the next meeting. What I need is a nextMeeting() function that will take any date as input and tell me the date of the next meeting, e.g., nextMeeting({9/29/98}) should evaluate to {10/14/98}. E-mail your function to me. I'll post the most elegant and original solution and post the names of all Alphaphiles who come up with working solutions. Please, the New York Alpha User Group is counting on you!
9/29/98 - pkw
Don't forget, we need your feedback to make this site better!