Gregorian Calendar for Windows Command Prompt

If like me you are one who spends a lot of time working and scripting with cmd.exe, sometimes it is handy to be able to quickly view a calendar for a given month and year. This script will quickly do just that!  Save the code posted below to a .bat file called gcal.bat.  Then you will be able to view the current calendar (default) or specify a month and year, all with a simple command:

  gcal  [month]  [YYYY]


  gcal  July
  gcal  August 2012
  gcal  09 2012
  gcal  10/2012
  gcal  nov .  dec .  jan 2013

Notes:  This is a pure script solution - no additional third party tools or scripts are required.  (EDIT: I now use the wmic program that comes with the OS to get the default month and year in a regionally non-dependant manner, but I left the "pure script" version in for reference, and for use with older OS versions.  See the formatParams section.)

The script is divided into four sections.  The first section (formatParams) validates and formats the input parameters (if any).  For flexibility the script will take various month formats.  The years is always a number from 1-9999.

The second section (getDayList) simply builds a string of numbers to represent the days in the specified month, 1 - 28, 29, 30, or 31 as required.

The third section (getSTARTDOW) actually does the work - determining which day of the week is the first of the month specified.

The fourth section (displayCalendar) displays the calendar by pulling sub-strings from the data build in section 2 - one for each week of the month.

Finally, it should be noted that the Gregorian calendar was first adapted in 1582, and gained widespread acceptance in 1752.  Therefore, renderings of the Gregorian calendar prior to these dates are just projections.

Edit 2016-02-01 - added a feature to surround the current day in brackets when the current month is rendered. Also some minor bug fixes.

Now the script!

@echo off
                       setlocal DISableDelayedExpansion
                      :REM      gcal.bat - Gregorian Calendar
                      :REM      written by:  Ralph L. Brown
                      :REM      syntax: gcal.bat [month] [YYYY] ...
                       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
                      :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%
                      :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%
                      :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
                       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%
                      :writeWeek - This section extracts the specified week from the dayList string.
                       set/a _idx=%1*28-4*%STARTDOW%
                       call set week=%%dayList:~%_idx%,28%%
                       exit/b 0
                      :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
                       set msg=%*
                      @echo. %msg:\n=&@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

Open in new window


Comments (1)

Good script! I'll be using it in one of my powershell programmes.

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.