REXX inside and out - Date()

From EDM2
Jump to: navigation, search

Written by Joe Wyatt

REXX Inside and Out

How about a Date()?

Ideas for columns come from questions posed in the forums on the internet. I don't hang around alt.letters.lovelorn.ducttape and such where one might expect to get an idea for a title like this, but one question that I have seen quite a bit on programming forums is "How do I do date manipulation in REXX?". Today, class, we are going to take a look at how to do just that.

This is a controversial subject. When one of these questions is asked, there are at least five answers with different solutions and each responder believes his/her solutions to be the best. The solutions provided will be in native REXX so that you may examine the logic used to derive them (and use them on other platforms!), but they will also be provided as compiled C routines in the EDMRexx DLL. You are free to use either of these forms, but the routines in the DLL package are a bit easier.

One Man's Way

The RexxDate() function returns a 'base date' when given the parameter "B". This base date is defined as the number of complete days since (and including) January 1, 0001. There are a number of caveats in online REXX documentation concerning this definition and, although they do not effect our date manipulation methods for normal dates, they should be reviewed for special cases. If you subtract two base dates, one from another, the result is the number of days between the dates. The problem with REXX's date() function is that it only works on the current date, so getting the second base date to subtract can be a bit tricky.

On to the scene steps EDMBaseDateG(). EDMBaseDateG() takes the elements from a Gregorian date and returns a base date. A REXX version of this function follows:

/* EDMBaseDateG(year, month, day) */
/* convert Gregorian date to REXX's "base date" */
/* wyatt 1996 */

yyyy    =arg(1)
mm      =arg(2)
dd      =arg(3)

/* add current century if necessary */
If(length(yyyy) = 2) Then
   yyyy =substr(date("S"), 1, 2) || yyyy

c = (365 *yyyy) + dd + (31 * (mm - 1)) - 366
if mm < &space 3 then
  return(c + (yyyy-1)%4 - (.75*(((yyyy-1)/100+1)%1)) % 1)

else
  return(c-(0.4*mm+2.3)%1+(yyyy%4)-(.75*((yyyy%100)+1))%1)

Figure 1) Calculating a base date.

Note: EDMBaseDateJ(year,days) also exists in the DLL for converting Julian dates to base date format.

Now it is simple to calculate the difference between dates! The equation

days =date("B") - EDMBaseDateG(1996, 2, 25)

will calculate the number of days between today's date and the date I should have submitted this column to the magazine. Base date is also a key value for the remaining date function.

EDMDate()

Several different ideas swam around my otherwise empty head concerning what other functions needed to be included this month. It was finally decided that the REXX programmer would be most familiar with a function that was similar in nature to the built in date() function. And if you are not familiar with this function then it is high time that you did a little studying about it. EDMDate() was made exactly like REXX's date() function except that it accepts a second parameter. You guessed it, besides the indicator of what date format to return, a base date to act upon is sent to the EDMDate() function as well.

EDMDate(format, baseDate) is the basic call format for the function. The first parameter, format, matches those for the date() function with one exception. EDMDate() does not have a "Basedate" format. It would have been very easy to implement and I thought about doing so for completeness' sake, but thought that it might be just a little silly to write a function that returned one of its parameters. Let's go through the included formats now.

  • "Days" - Returns the number of days, including the current day, so far in this year in the format:ddd (no leading zeros)
  • "European" - Returns date in the format: dd/mm/yy.
  • "Language" - Returns date in an implementation and language- dependent or local date format. In the OS/2 operating system. Language format is "dd Monthyyyy". If no local format is available, the default format is returned.
  • "Month" - Returns full English name of the current month, for example, August
  • "Normal" - Returns date in the default format: dd mon yyyy
  • "Ordered" - Returns date in the format: yy/mm/dd (suitable for sorting, and so on.)
  • "Sorted" - Returns date in the format: yyyymmdd (suitable for sorting, and so on.)
  • "Usa" - Returns date in the format: mm/dd/yy
  • "Weekday" - Returns the English name for the day of the week, in mixed case. For example, "Tuesday".

Just like the date() function, only the upper case, first character of the format key word is required, but please be aware of a common mistake. Many new REXX programmers do not quote the format string. This may or may not cause problems.

The program below works fine.

/* say the week day */
saydate(w)
exit

but the following, similar one does not.

/* count to seven then croak */
do w=1 to 7 by 1
   say "W is now="w
end

say date(w) /* oops! what does w equal here? */

The default value of uninitialized variables in REXX is the upper case name of the variable. In the first sample the argument, w, was taken by REXX to be an uninitialized variable so the "Weekday" format was requested. The second example used the variable, w, in a loop earlier in the program so the current value of the variable was sent instead of the expected "W". This seems like a silly mistake, but it is quite common. (yes, I have done it too)

Speaking of silly...It should be noted that I took a short cut on the way the DLL checks the parameters. The EDMDate function only checks the first character. So if you execute EDMDate("Doofus", basedate) you will get the number of days so far in the year.

I Don't Kiss on the First Date()

You might not be too wild about the implementation that I have presented here. If you have some serious reservations about the way this DLL might function or just think that I have committed great coding/algorithmic errors then let me know. As mentioned earlier, this is a controversial subject and everyone believes his/her own solution to be best. So by all means, drop me some E-mail, and we can roll up our sleeves and go to the alley to discuss it like civilized ladies and gentlemen. [wink]