@echo off
setlocal DISableDelayedExpansion
:REM gcal.bat - Gregorian Calendar
:REM written by: Ralph L. Brown
:REM syntax: gcal.bat [month] [YYYY] ...
:START
@echo.
set params=%~1/%~2
set params=%params:/= %
set params=%params:-= %
call :formatParams %params% || exit/b 1
call :getDayList
call :getSTARTDOW
call :displayCalendar
set _p1=%~1
if "%_p1%" == "%_p1:/=%" shift /1
shift /1
if not "%1"=="" goto :START
exit/b 0
:END MAIN
:formatParams - This section validates the month and year parameters (if supplied).
set currentDate=%date:~10,4%%date:~4,2%%date:~7,2%
set/a currentDate+=0 2>nul
REM - if the above fails, then get these fields using a regionally independent method:
if NOT "%currentDate%"=="%date:~10,4%%date:~4,2%%date:~7,2%" for /f "delims= " %%C in ('wmic path Win32_LocalTime Get Day^,Month^,Year /Format:List 2^>nul ^| find "="') do @(set current%%C) 2>nul
REM - but this way is generally faster...
if not defined currentYear set/a currentYear=%currentDate:~0,4%
if not defined currentMonth set/a currentMonth=%currentDate:~0,6% %% %currentDate:~0,4%00
if not defined currentDay set/a currentDay=%currentDate% %% %currentDate:~0,6%00
call :decode "%currentMonth%" "1:JAN,JAN:JAN,2:FEB,FEB:FEB,3:MAR,MAR:MAR,4:APR,APR:APR,5:MAY,MAY:MAY,6:JUN,JUN:JUN,7:JUL,JUL:JUL,8:AUG,AUG,08:AUG,AUG:AUG,9:SEP,SEP,09:SEP,SEP:SEP,10:OCT,OCT:OCT,11:NOV,NOV:NOV,12:DEC,DEC:DEC"
set currentMonth=%decode%
set/a calMonth=%~1 2>nul || set calMonth=%~1
if 0%calMonth% equ 0 set calMonth=%~1
if "%calMonth%"=="" set calMonth=%currentMonth%
if "%calMonth%"=="." set calMonth=%currentMonth%
call :decode "%calMonth:~0,3%" "1:JAN,JAN:JAN,2:FEB,FEB:FEB,3:MAR,MAR:MAR,4:APR,APR:APR,5:MAY,MAY:MAY,6:JUN,JUN:JUN,7:JUL,JUL:JUL,8:AUG,AUG,08:AUG,AUG:AUG,9:SEP,SEP,09:SEP,SEP:SEP,10:OCT,OCT:OCT,11:NOV,NOV:NOV,12:DEC,DEC:DEC"
set calMonth=%decode%
if not defined calMonth call :syntax Invalid month specified: "%~1"\n Valid range is 1-12, or month name (or abbreviation), or . for current month. || exit/b 1
set calYear=%~2
if "%calYear%"=="." set calYear=
if defined calYear set calYear=%calYear:X=#%
if defined calYear set/a calYear=%calYear% 2>nul
if defined calYear if NOT "%calYear%"=="%~2" set calYear=INVALID
for %%Y in (00,01,02,03,04,05,06,07,08,09) do if "%~2"=="%%Y" set calYear=%currentYear:~0,2%%%Y
if NOT defined calYear set calYear=%currentYear%
REM - Comment-out the next 2 lines if you want to render years 1 A.D. - 99 A.D.
if %calYear% LSS 10 set calYear=%currentYear:~0,2%0%calYear%
if %calYear% LSS 100 set calYear=%currentYear:~0,2%%calYear%
if %calYear% LSS 10000 if %calYear% GEQ 0 exit/b 0
call :syntax Invalid year specified: "%~2"\n Valid range is 100 - 9999, or . for current year.
exit/b 1
:END-formatParams
:getDayList - This section creates the string of days for the specified month.
set/a leapYear= !(%calYear% %% 4) - !(%calYear% %% 100) + !(%calYear% %% 400) 2>nul
set dayList=++++++1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
if "%calMonth%"=="FEB" if %leapYear% equ 1 set dayList=%dayList% 29
if not "%calMonth%"=="FEB" set dayList=%dayList% 29 30
for %%M in (JAN,MAR,MAY,JUL,AUG,OCT,DEC) do if "%calMonth%"=="%%M" set dayList=%dayList% 31
set dayList=%dayList:+= %
if %currentYear% equ %calYear% if "%currentMonth%"=="%calMonth%" call set dayList=%%dayList: %currentDay% =[%currentDay%]%%
exit/b %errorlevel%
:END-getDayList
:getSTARTDOW - This section determines which day of the week falls on the 1st of the month (0 - 6 for Sun - Sat).
set/a workYear=%calYear% %% 400 2>nul
set/a DOWJAN1= ( ( ( %workYear% %% 28 ) + ( ( (%workYear%+3) %% 28) / 4 ) ) + (( 6 * ( 1 + ((%workYear%-1) / 100)) ) ) ) %% 7
for %%M in (JAN,FEB) do if "%calMonth%"=="%%M" set leapYear=0
call :decode "%calMonth%" "JAN:0,FEB:3,MAR:3,APR:6,MAY:1,JUN:4,JUL:6,AUG:2,SEP:5,OCT:0,NOV:3,DEC:5"
set/a STARTDOW= ( %DOWJAN1% + %decode% + %leapYear% ) %% 7
exit/b %errorlevel%
:END-getSTARTDOW
:displayCalendar - This section displays the calendar.
set calYear= %calYear%||:This is to format the year for display.
@echo. %calMonth% %calYear:~-4%
@echo. Sun Mon Tue Wed Thu Fri Sat
@echo.
for /L %%W in (1,1,6) do call :writeWeek %%W
if %calYear% GTR 1752 exit/b %errorlevel%
@echo. NOTE: The Gregorian calendar was first adapted in 1582, but
@echo. only gained widespread acceptance in 1752. The calendar
@echo. above is a projection of how the Gregorian calendar would
@echo. have rendered had it been in use prior to September of 1752.
exit/b %errorlevel%
:END-displayCalendar
:writeWeek - This section extracts the specified week from the dayList string.
set/a _idx=%1*28-4*%STARTDOW%
call set week=%%dayList:~%_idx%,28%%
@echo.%week%
exit/b 0
:END-writeWeek
:decode - This function extracts the matching key value from the supplied map.
set key=%~1
set csvmap=,%~2
set ret=%~3
if "%ret%"=="" set ret=decode
call set key=%%csvmap:*,%key%:=%%
set %ret%=%key:,=&:%||exit/b 1
exit/b 0
:END-decode
:syntax
set msg=%*
@echo. %msg:\n=&@echo.%
@echo.
@echo. Syntax: %~nx0 [month] [YYYY] ...
@echo. Example: %~nx0 July
@echo. Example: %~nx0 August %currentYear%
@echo. Example: %~nx0 09 %currentYear%
@echo. Example: %~nx0 10/%currentYear%
set/a currentYear+=1
@echo. Example: %~nx0 nov . dec . jan %currentYear%
exit/b 1
:END-syntax
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (1)
Commented: