06-14-2004, 06:43 AM
Ok guys, here's my solution. I used a bunch of date handling routines that I already had. The actual Tuesday logic is a small FOR loop that's very simple. A more clever algorithm might be used, but why spend the energy.
You run the program with a command-line parameter of the "from" date you want in the format YYYYMMDD.
Try it out.
*****
You run the program with a command-line parameter of the "from" date you want in the format YYYYMMDD.
Try it out.
*****
Code:
REM *** Program to count number of Tuesdays from input date to today-1.***
DEFINT A-Z
DECLARE FUNCTION IsLeapYear% (Z)
DIM YEAR.MIN AS INTEGER 'Minimum valid year for dates (default=0)
DIM DATE.FACTOR AS SINGLE 'Number of days given date is from day zero.
DIM WEEK.DAY AS INTEGER 'Day of week value: 1=Sunday....7=Saturday.
DIM WEEK.NUM AS INTEGER 'Week number within year (1 to 54).
DIM JULIAN.DAY AS INTEGER 'Day number within year (1 to 366).
DIM DATE.OK AS INTEGER 'Valid date indicator: -1=True, 0=False.
Z$ = "" 'Date string as YYYYMMDD.
DIM ZYY AS INTEGER 'Value of the 4 digit year.
DIM ZMM AS INTEGER 'Value of the 2 digit month.
DIM ZDD AS INTEGER 'Value of the 2 digit day.
DIM ZDWORK AS LONG 'Variable internal to date routines.
DIM ZFSAVE AS SINGLE 'Variable internal to date routines.
DIM ZFSAVE2 AS SINGLE 'Variable internal to date routines.
ZTEMP$ = "" 'Work string internal to date routines.
'NOTE: The following variable ZMO() is internal to date routines.
DIM ZMO(1 TO 12) AS INTEGER
DATA 31,28,31,30,31,30,31,31,30,31,30,31
FOR ZMM=1 TO 12:READ ZMO(ZMM):NEXT
dim factor1 as single
dim factor2 as single
dim dtfact as single
dim tcount as long
REM *** MAIN LINE *************************************************************
param1$ = ltrim$(rtrim$(command$)) 'input date (from)
gosub date.today:param2$=z$
print param1$
print param2$
z$=Param1$
gosub date.factor
factor1=date.factor
if not(date.ok) then print "Invalid input date, must be YYYYMMDD":system
if param1$ >= param2$ then print "Input date >= today, nothing to do":system
z$=Param2$
gosub date.factor
factor2=date.factor
for dtfact=factor1 to factor2-1
date.factor=dtfact
gosub compute.weekday
if week.day=3 then tcount=tcount+1 'count Tuesdays (3)
next dtfact
print:print "Number of Tuesdays between ";param1$;" and today is ";tcount
SYSTEM
REM ************************ DATE.FACTOR ************************************
REM *
REM *** PRINCIPAL DATE SUBROUTINE:
REM * =========================
REM * - Validate input date string.
REM * - Compute number of days (date.factor) from year 0, month 0, day 0.
REM * - Compute day of week.
REM * - Compute week number.
REM * - Compute "julian" day of year.
REM *
REM * INPUT:
REM * =====
REM * Z$ = Date string formatted as YYYYMMDD.
REM * YEAR.MIN = Minimum year user wishes to allow (default 0)
REM *
REM * OUTPUT:
REM * ======
REM * DATE.OK = -1 if input date VALID. (true)
REM * = 0 if Input date INVALID. (false)
REM * NOTE: IF VALID, THE FOLLOWING VARIABLES AR BASED ON INPUT DATE.
REM * IF INVALID, THE VALUES MAY HAVE CHANGED AND ARE MEANINGLESS.
REM * DATE.FACTOR = Number of cumulative days from year/month/day 0.
REM * WEEK.DAY = 1 to 7 is Sunday to Saturday respectively.
REM * WEEK.NUM = 1 TO 54 is week number within year.
REM * JULIAN.DAY = 1 TO 366 is day number within year.
REM * ZYY = Value of of 4 digit year.
REM * ZMM = Value of month.
REM * ZDD = Value of day.
REM * EASTERSUNDAY$ = Date of Easter for given year.
REM * Z$ = (unchanged).
REM * YEAR.MIN = (unchanged).
REM *
REM *
REM * Date factor logic adopted from a Texas Instruments calculator manual.
REM *
DATE.FACTOR:
gosub Date.Check 'check input date
if not(date.ok) then RETURN 'exit if invalid
zmm=1:zdd=1 'set to January 1st
gosub Compute.Factor 'compute factor of Jan 1st
zfsave=date.factor 'save factor of Jan 1st
gosub Compute.Weekday 'week.day now has day of week of Jan 1st
zdd=val(right$(z$,2)) 'Restore input date's day + month
zmm=val(mid$(z$,5,2))
gosub Compute.Factor 'compute factor of input date
'* Julian day is input date minus Jan 1st of same year +1
julian.day=date.factor-zfsave+1
'* Compute the week number: (week.day-1 is week day of Jan 1st relative to 0)
week.num=int((julian.day+(week.day-1)-1)/7)+1
'* Compute the day of the week of input date:
gosub Compute.Weekday
RETURN
COMPUTE.FACTOR:
DATE.FACTOR=365!*ZYY+ZDD+31*(ZMM-1) 'NOTE: WON'T WORK WITHOUT ! AFTER 365.
IF ZMM<3 THEN
DATE.FACTOR=DATE.FACTOR+INT((ZYY-1)/4)-INT(3/4*(INT((ZYY-1)/100)+1))
ELSE
DATE.FACTOR=DATE.FACTOR-INT(.4*ZMM+2.3)+INT(ZYY/4)-INT(3/4*(INT(ZYY/100)+1))
END IF
RETURN
COMPUTE.WEEKDAY:
'* Compute the day of the week:
WEEK.DAY=DATE.FACTOR-INT(DATE.FACTOR/7)*7 'Modulo 7.
IF WEEK.DAY=0 THEN WEEK.DAY=7 'WEEK.DAY=1=Sunday.
RETURN
REM ****************** DATE.TODAY *******************************************
REM *
REM *** SUBROUTINE TO GET TODAY'S DATE AND FORMAT AS YYYYMMDD.
REM *
REM * INPUT: (None)
REM *
REM * OUTPUT: Z$ = Today's date, string as YYYYMMDD.
REM *
DATE.TODAY:
z$=date$ 'Date is mm-dd-yyyy
if left$(time$,2)="00" then z$=date$ 'make sure date didn't just roll over
Z$=right$(z$,4)+left$(z$,2)+mid$(z$,4,2) 'in YYYYMMDD format
RETURN
REM ********************* DATE.CHECK ****************************************
REM *
REM *** VALIDATE A DATE IN YYYYMMDD FORMAT.
REM *
REM * INPUT: Z$ = Given date in format YYYYMMDD.
REM * YEAR.MIN = Minimum valid year allowed. (default=0)
REM *
REM * OUTPUT: DATE.OK = -1 if input date is VALID. (true)
REM * 0 if input date is INVALID. (false)
REM * (if VALID):
REM * ZYY = Value of 4 digit year.
REM * ZMM = Value of month.
REM * ZDD = Value of day.
REM *
REM *
DATE.CHECK:
DATE.OK = 0 'preset to false
ZTEMP$="1"+Z$+"1"
IF LEN(Z$)<>8 OR MID$(STR$(VAL(ZTEMP$)),2)<>ZTEMP$ THEN RETURN
ZDD=VAL(RIGHT$(Z$,2)) 'Set day
ZMM=VAL(MID$(Z$,5,2)) 'Set month.
ZYY=VAL(LEFT$(Z$,4)) 'Set year.
IF ZMM<1 OR ZMM>12 OR ZDD<1 OR ZDD>31 OR ZYY<YEAR.MIN THEN RETURN
IF ZMO(ZMM)+1*(-(ZMM=2 AND ISLEAPYEAR(ZYY))) < ZDD THEN RETURN
' If expression (month=2 and is leapyear) is TRUE which is -1, then
' taking the negative of this issues a plus 1. Conversely, the FALSE
' always gives a zero. Multiplying the +1 by this result of 1 or 0
' will either add 1 or not to the number of days in the month.
' The routine wants to add 1 only when it is February and leap year.
DATE.OK = -1 '-1=valid (true)
RETURN
REM ***************************************************************************
END
' ====================== ISLEAPYEAR ==========================
' Determines if a year is a leap year or not.
' ============================================================
'
FUNCTION IsLeapYear (Z) STATIC
' If the year is evenly divisible by 4 and not divisible
' by 100, or if the year is evenly divisible by 400, then
' it's a leap year:
IsLeapYear = (Z MOD 4 = 0 AND Z MOD 100 <> 0) OR (Z MOD 400 = 0)
END FUNCTION