~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Calculating the number of days in a month
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The number of days each month is as follows;
Name Number NumerofDays
---------------------------------------------
Jan 01 31
Feb 02 29 if leap year, otherwise 28
Mar 03 31
Apr 04 30
May 05 31
Jun 06 30
Jul 07 31
Aug 08 31
Sep 09 30
Oct 10 31
Nov 11 30
Dec 12 31
---------------------------------------------
So given that %MM% holds the current month
you almost have a very simple solution in;
SET _=31
FOR %%_ IN (04 06 09 11) DO IF %MM%==%%_ SET _=30
%_% is now the correct number of days in the month
for all of the months except February.
At least we know that we could have the next line;
IF NOT %MM%==02 %RET%
February makes things a bit more difficult for us,
we need to check the year and find out whether or
not it is a leap year in order to get the correct
answer.
A leap year occurs when these conditions are satisfied;
(i) The year must be divisible by 4
(ii) If the year is divisible by 100 then it
must be divisible by 400 also.
Using the year variables %YH% and %YL% (YH=century,
YL=year mod100) it is simple to see that there
are only 2 cases to check;
(i) If YL=0 then ISLEAPYEAR:= { YH divisible by 4 }
(ii) If YL!=0 then ISLEAPYEAR:= { YH,YL divisible by 4 }
(ii) can be further simplified by noticing that if
the least 2 significant digits of a value are divisible
by 4 then the whole number is divisible by 4 (This is
due to the fact that the number YEAR can be written
as YH*100+YL = (YH*25)*4+YL )
Then we have;
(ii) If YL!=0 then ISLEAPYEAR:= { YL divisible by 4 }
How to check divisibility by 4?? Easy, since we now know
we only have to check a 2 digit value a simple exhaustive
check on all the 25 possibilities can be done with a
FOR loop;
FOR %%_ IN (00 04 08 12 16 20 24 28 32 36 40 44) DO IF %_%==%%_ SET _=ABC
FOR %%_ IN (48 52 56 60 64 68 72 76 80 84 88 92 96) DO IF %_%==%%_ SET _=ABC
IF %_%==ABC ECHO VALUE IS DIVISIBLE BY 4!
Now, look again at the rules we have;
(i) If YL=0 then ISLEAPYEAR:= { YH divisible by 4 }
(ii) If YL!=0 then ISLEAPYEAR:= { YL divisible by 4 }
You may notice how similar they are. In fact they could be
rewritten into one;
@=%YL%
IF YL=0 then @=%YH%
ISLEAPYEAR:= { @ divisible by 4 }
This works out very nicely in DOS batch code;
:: get value to check, either YL or YH
SET _=%YH%
IF NOT %YL%==00 SET _=%YL%
:: a little fixup, 29 is used as the marker for divisibility by 4
:: check succeeding so we don't want it to be a possible input value
:: changing a value 29 to 01 here won't change the result, it's
:: still not divisible by 4
IF %_%==29 SET _=01
:: check %_% for divisibility by 4, if (and only if) it is divisible
:: by 4 will the 2 loops complete with %_%=29
FOR %%_ IN (00 04 08 12 16 20 24 28 32 36 40 44) DO IF %_%==%%_ SET _=29
FOR %%_ IN (48 52 56 60 64 68 72 76 80 84 88 92 96) DO IF %_%==%%_ SET _=29
:: If its not a multiple of 4 then the number of days in Feb
:: will be 28
IF NOT %_%==29 SET _=28
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The complete subroutine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::************************************************************
::* DIMTH - CALCULATE DAYS IN MONTH *
::* Entry: %YH%,%YL%=YEAR %MM%=MONTH *
::* Exit: %_%=DAYS IN MONTH *
::* Last Modified: 30/10/00 *
::* Compatibility: DOS 5+ (Tested: DOS 7) *
::* Notes: This is optimised version with leap year routine *
::* integrated into it. *
::************************************************************
:DIMTH
SET _=31
FOR %%_ IN (04 06 09 11) DO IF %MM%==%%_ SET _=30
IF NOT %MM%==02 %RET%
SET _=%YH%
IF NOT %YL%==00 SET _=%YL%
IF %_%==29 SET _=01
FOR %%_ IN (00 04 08 12 16 20 24 28 32 36 40 44) DO IF %_%==%%_ SET _=29
FOR %%_ IN (48 52 56 60 64 68 72 76 80 84 88 92 96) DO IF %_%==%%_ SET _=29
IF NOT %_%==29 SET _=28
%RET%
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~