I'd like to present a couple of date manipulation routines and accept your praise for the wonderful algorithms.

I'd like to, but I can't as they're not mine - I transliterated them from an article that I found on the web. Credit goes to Peter Baum whos document it is. The document can be found at:
http://www.capecod.net/~pbaum/date/date0.htm

If you use the scripts please keep the reference to Peters document as per his request. You should also refer to this page to see the limitations of the algorithms - suffice to say that they should be fine for business use, but if you want to use them to calculate to first Tuesday of the Jurassic forget it.

Now, the code. I keep these type of scripts in a "library" directory - you can of course copy them straight into a script and use them as subroutines if you prefer. There are two scripts, one to convert a calendar date into an internal integer representation (intdate.kix) and one to convert the internal representation back to the calendar format.

code:
;
; intdate.kix
; Library routine to convert a date from Calendar to internal format.
;
; The algorithm used here is taken directly from the following document:
; http://www.capecod.net/~pbaum/date/date0.htm
;
; Variables passed:
; rd_day IN Day of month (0-31)
; rd_month IN Month of year (1-12)
; rd_year IN Full year
; rd_internal OUT Internal representation
;
; Amendment history:
; Version 1.0 21 June 2000 Richard Howarth
;

GLOBAL $rd_day,$rd_month,$rd_year,$rd_internal
DIM $MyYear,$MyMonth

$MyYear=$rd_year
$MyMonth=$rd_month

if $MyMonth < 3
$MyMonth = $MyMonth + 12
$MyYear = $MyYear - 1
endif

$rd_internal = $rd_day + ( 153 * $MyMonth - 457 ) / 5 + 365 * $MyYear + $MyYear / 4 - $MyYear / 100 + $MyYear / 400 - 306

RETURN



code:
;
; extdate.kix
; Library routine to convert a date from internal to Calendar format.
;
; The algorithm used here is taken directly from the following document:
; http://www.capecod.net/~pbaum/date/date0.htm
;
; Variables passed:
; rd_day OUT Day of month (0-31)
; rd_month OUT Month of year (1-12)
; rd_year OUT Full year
; rd_internal IN Internal representation
;
; Amendment history:
; Version 1.0 21 June 2000 Richard Howarth
;

GLOBAL $rd_day,$rd_month,$rd_year,$rd_internal
DIM $MyZ,$MyH,$MyA,$MyB,$MyC

$MyZ=$rd_internal + 306
$MyH=100*$MyZ-25
$MyA=$MyH/3652425
$MyB=$MyA-$MyA/4
$rd_year=(100*$MyB+$MyH)/36525
$MyC=$MyB+$MyZ-365*$rd_year-$rd_year/4
$rd_month=(5*$MyC+456)/153
$rd_day=$MyC-(153*$rd_month-457)/5

if $rd_month > 12
$rd_year=$rd_year + 1
$rd_month = $rd_month - 12
endif

RETURN



As you can see the code is very small, and it executes very quickly.

Just to show I'm not completely clueless, here are a couple of scripts which test the routines - you don't need any of these to use the routines, they here as examples.

test_1.kix iterates the dates from 1 Jan 1900 'till 1 Jan 2001. It is a simple check that the results of the two routines complement each other.

test_2.kix is more of a real world application. It'll accept a date, parse it and validate it. You can then apply a modifier. A positive number will advance the date, a negative one will reverse it.

code:
;
; test_1.kix
; Test date conversion routines.
; Iterate the dates between 1 Jan 1900 and 1 Jan 2001
;
; Amendment history:
; Version 1.0 21 June 2000 Richard Howarth

BREAK ON

GLOBAL $rd_day,$rd_month,$rd_year,$rd_internal
DIM $Months[13]

$Months[1]="Jan"
$Months[2]="Feb"
$Months[3]="Mar"
$Months[4]="Apr"
$Months[5]="May"
$Months[6]="Jun"
$Months[7]="Jul"
$Months[8]="Aug"
$Months[9]="Sep"
$Months[10]="Oct"
$Months[11]="Nov"
$Months[12]="Dec"

; Start at 01 Jan 1900
$IntDate=693596

WHILE $rd_year < 2001

$rd_internal=$IntDate
CALL extdate.kix ; Convert to Calendar
$rd_internal=0 ; No Cheating!!
CALL intdate.kix ; Convert to internal

"Day $IntDate is $rd_day " $Months[$rd_month] " $rd_year " chr(13)
if $IntDate <> $rd_internal
? "Sanity check mismatch: IS $rd_internal, S/B $IntDate" ?
RETURN
endif

$IntDate = $IntDate + 1
LOOP


If you want to use the test_2.kix script you will also need the strtok.kix script which I use to parse the date.

code:
;
; test_2.kix
; Test date conversion routines.
; Input a date in DD/MM/YYYY format, validate is then perform math on it.
;
; Amendment History:
; Version 1.0 21 June 2000 Richard Howarth

BREAK ON

; Globals for date routines.
GLOBAL $rd_day,$rd_month,$rd_year,$rd_internal

; Globals for token routines.
GLOBAL $TokenFS,$TokenIN,$Token,$TokenERR

DIM $Date,$Modifier,$Months[13],$InternalDate

$Months[1]="Jan"
$Months[2]="Feb"
$Months[3]="Mar"
$Months[4]="Apr"
$Months[5]="May"
$Months[6]="Jun"
$Months[7]="Jul"
$Months[8]="Aug"
$Months[9]="Sep"
$Months[10]="Oct"
$Months[11]="Nov"
$Months[12]="Dec"

color w/n "Enter date as DD/MM/YYYY, or return to exit: " gets $Date
WHILE $Date <> ""
GOSUB "ValidateDate"
if $Date<> ""
$InternalDate=$rd_internal
? color y+/n "Enter modifier, or return to exit: " gets $Modifier
WHILE $Modifier <> ""
$InternalDate=$InternalDate + val($Modifier)
$rd_internal=$InternalDate
CALL extdate.kix
" Date is now $rd_day " $Months[$rd_month] " $rd_year" ?
color y+/n "Enter modifier, or return to exit: " gets $Modifier
LOOP
endif
? color w/n "Enter date as DD/MM/YYYY, or return to exit: " gets $Date
LOOP

RETURN

; ************************
; Validate Date subroutine
; ************************
:ValidateDate

$TokenFS="/"
$TokenIN=$Date
$Date=""

$TokenERR=1

CALL strtok.kix
if $TokenERR color r+/n " Error parsing day of month or invalid date." ? RETURN endif
$MyDay=val($Token)
$rd_day = $MyDay

CALL strtok.kix
if $TokenERR color r+/n " Error parsing month or invalid date." ? RETURN endif
$MyMonth=val($Token)
$rd_month = $MyMonth

CALL strtok.kix
if $TokenERR color r+/n " Error parsing year or invalid date." ? RETURN endif
$MyYear=val($Token)
$rd_year = $MyYear

; Convert to internal then back again. If the values match then the date is
; probably valid.
CALL intdate.kix
CALL extdate.kix
if "$MyDay/$MyMonth/$MyYear" = "$rd_day/$rd_month/$rd_year"
$Date="OK"
" Ok, date validates as $rd_day/$rd_month/$rd_year" ?
else
color r+/n " You entered $MyDay/$MyMonth/$MyYear, but my check returned $rd_day/$rd_month/$rd_year" ?
color r+/n " I interperet that as an invalid date." ?
endif
RETURN


code:
;
; strtok.kix
; Kix library function - tokenize string.
; Each time this routine is called it will set $Token to the next field in
; $TokenIN. The field seperator is defined in $TokenFS. $TokenIN is reset
; for subsequent calls.
;
; $TokenFS IN Field Seperator(s) (default is comma)
; $TokenIN IN String to be tokenized.
; $Token OUT Token found.
; $TokenERR OUT 0=valid token, 1=Out of tokens
;
; Amendment History:
; Version 1.0 16 June 2000 Richard Howarth

$_MyTokenReset="___TokenIN reset by tokenizer___"

$Token=""
$TokenERR=1

if $TokenFS = "" $TokenFS="," endif

if $TokenIN <> $_MyTokenReset
$_MyTokenIN=$TokenIN
$_MyTokenLen=len($TokenIN)
$_MyIndex=0
$TokenIN=$_MyTokenReset
if $_MyTokenIN = ""
$TokenERR=0
RETURN
endif
endif

if $_MyTokenIN = "" RETURN endif
if $_MyIndex > $_MyTokenLen RETURN endif

$TokenERR=0
while 1
$_MyIndex=$_MyIndex + 1
if $_MyIndex > $_MyTokenLen RETURN endif
$_T = substr($_MyTokenIN,$_MyIndex,1)
if instr($TokenFS,$_T) RETURN endif
$Token=$Token+$_T
loop


Richard Howarth.

[This message has been edited by rhowarth (edited 21 June 2000).]

[This message has been edited by rhowarth (edited 21 June 2000).]