Date arithmetic in cmd scripting

I need to write a script to change a filename from aDate.txt to bDate.txt where:

  • aDate is the current system date in yyyymmdd format and
  • bDate is the current system date - 1 in yyyymmdd format.

I currently have:

set yy=%date:~6,2%
set mm=%date:~3,2%
set dd=%date:~0,2%
if "%date:~6,1%"==" " set yy=0%yy:~1,1%
if "%date:~3,1%"==" " set mm=0%mm:~1,1%
if "%date:~0,1%"==" " set dd=0%dd:~1,1%
SET sys_date=20%yy%%mm%%dd%
ECHO %sys_date%
REM still have to do this bit properly
SET sys_date_yesterday=%sys_date%a
move %sys_date%.txt %sys_date_yesterday%.txt

but I have no idea how to do the date -1 thing (other than the long winded) subtract 1 from the day and if that is = 0 then subtract one from the month and set the day = to the last day of the new month and so on for years.

Any ideas?


You have to do it the difficult way. I suggest to use this solution by SteveGTR. I copy the text below, because at least at least I cannot always see the solution on that site.


Here's a batch file I developed to subtract any number of days from the current date. It accepts a command line parameter of the number of days. The default is 1 day (yesterday):

@echo off

set yyyy=

set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ('date /t') do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ('date /t') do (
 for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ('echo.^|date') do (
    set %%x=%%u
    set %%y=%%v
    set %%z=%%w
    set $d1=
    set $tok=))

if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100

set CurDate=%mm%/%dd%/%yyyy%

set dayCnt=%1

if "%dayCnt%"=="" set dayCnt=1

REM Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100

:CHKDAY

if /I %dd% GTR 0 goto DONE

set /A mm=%mm% - 1

if /I %mm% GTR 0 goto ADJUSTDAY

set /A mm=12
set /A yyyy=%yyyy% - 1

:ADJUSTDAY

if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
REM ** Month 12 falls through

:SET31

set /A dd=31 + %dd%

goto CHKDAY

:SET30

set /A dd=30 + %dd%

goto CHKDAY

:LEAPCHK

set /A tt=%yyyy% %% 4

if not %tt%==0 goto SET28

set /A tt=%yyyy% %% 100

if not %tt%==0 goto SET29

set /A tt=%yyyy% %% 400

if %tt%==0 goto SET29

:SET28

set /A dd=28 + %dd%

goto CHKDAY

:SET29

set /A dd=29 + %dd%

goto CHKDAY

:DONE

if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%

echo Date %dayCnt% day(s) before %CurDate% is %mm%/%dd%/%yyyy%

Good Luck, Steve


Easily Add or Subtract Days from a Date with a Windows Batch Script

Here's a solution I came up with for calculating date (add or subtract) with a batch script. Set the variables accordingly for your needs and then adjust the logic as need for your needs as well. This works very well for my needs and it's all contained to the same one batch script without too much logic.

To add: You can also use this script to add a number of days to the current date by deleting the minus (-) symbol from the below batch script in the :DynamicVBSScriptBuild routine, so where you see this,-%MinusDay%, you simple remove the minus symbol to get ,%MinusDay%, on each of those lines and now the MinusDay= variable value will equal the number of days you want to add.

Important Note: It seems that five 9's (99999) is the limit on the batch script when subtracting with the MinusDays= value. It also seems that six 9's (999999) is the limit on the batch script when adding with the MinusDays= value.

Batch Script

@ECHO ON

::// Minus days is the number of days to subtract from the CURRENT DAY i.e. 2 for minus 2 days or 99999 for minus 99999 days from when it's run
SET MinusDay=2

:: This calls the temp vbs script routine that will be used to set YYYY-MM-DD values for the subtracted days date you specify
CALL :DynamicVBSScriptBuild

FOR /F "TOKENS=*" %%A IN ('cscript//nologo "%YYYYTmpVBS%"') DO SET YYYY=%%A
FOR /F "TOKENS=*" %%A IN ('cscript//nologo "%MMTmpVBS%"') DO SET MM=%%A
FOR /F "TOKENS=*" %%A IN ('cscript//nologo "%DDTmpVBS%"') DO SET DD=%%A

::// Set your web server log file path in the below variable
SET WebServerLogPath=C:\WebServer\Logs

::// Set web server log file name where YYYY MM DD variables are set to the values after the day numbers setup above are subtracted
SET YYYY=%YYYY%
SET MM=%MM%
SET DD=%DD%

ECHO %YYYY%%MM%%DD%
PAUSE

GOTO EOF

:DynamicVBSScriptBuild
SET YYYYTmpVBS=%temp%\~tmp_yyyy.vbs
SET MMTmpVBS=%temp%\~tmp_mm.vbs
SET DDTmpVBS=%temp%\~tmp_dd.vbs
IF EXIST "%YYYYTmpVBS%" DEL /Q /F "%YYYYTmpVBS%"
IF EXIST "%MMTmpVBS%" DEL /Q /F "%MMTmpVBS%"
IF EXIST "%DDTmpVBS%" DEL /Q /F "%DDTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%YYYYTmpVBS%"
ECHO yyyy = Year(dt)                    >> "%YYYYTmpVBS%"
ECHO WScript.Echo yyyy                  >> "%YYYYTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%MMTmpVBS%"
ECHO mm = Right("0" ^& Month(dt),2)     >> "%MMTmpVBS%"
ECHO WScript.Echo mm                    >> "%MMTmpVBS%"
ECHO dt = DateAdd("d",-%MinusDay%,date) >> "%DDTmpVBS%"
ECHO dd = Right("0" ^& Day(dt),2)       >> "%DDTmpVBS%"
ECHO WScript.Echo dd                    >> "%DDTmpVBS%"
GOTO EOF

Further Resources

  • FOR /F
  • CSCRIPT
  • WSCRIPT
  • DateAdd
  • Right

I needed something that would subtract days from the current date while checking leap years, etc. and this worked great.

I just call it from those scripts with the needed parameter (number of days to subtract), and then have it call back the calling script with substitutions and pass a parameter back to the original script for the modified (subtracted) date.

Here are examples:

Script needing date calculation variable set:

IF "%1"=="" goto modifydate

:modifydate
SET subtractdays=5
SET ModDateScript=\\servershare\path\Called_Scripts\ModDate.cmd
CALL "%ModDateScript%" %subtractdays% "%~fnx0"

Script which will calculate and pass back a %moddate% parameter to the original calling script to be set as a variable for it to process accordingly. You will simply put this at the end of the script you call to modify/subtract days from the current date (ModDate.cmd).

SET moddate=%mm%/%dd%/%yyyy%
Call %2 %moddate%
GOTO EOF

I was able to test and determine that these lines from the original script posted:

set yyyy=
set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ('date /t') do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ('date /t') do (
for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ('echo.^|date') do (
    set %%x=%%u
    set %%y=%%v
    set %%z=%%w
    set $d1=
    set $tok=))
if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100

Can be replaced with just this one single line and it works just as well:

FOR /F "tokens=2-4 delims=/ " %%A IN ("%date%") DO SET "mm=%%A" DO (& SET "dd=%%B") DO (& SET "yyyy=%%C")

Please explain what those lines (the ones I changed to just the one line with and statements) do anyways because I cannot tell the difference quickly testing. I subtracted back to the 19th century and it appeared accurate to me. I thought perhaps it helped handle the calculations where the modified year would be less than 2000 -- but I didn't see that unless I'm missing something.

Otherwise this one script can be easily called and pass back the %mm%/%dd%/%yyyy% as a parameter for several scripts which need their own calculations. Great and very efficient batch solution. I can pass the argument as %1, %2, %3, etc. and still use the setlocal in that script for the current date -- just make a variable something like moddate=%1, etc.

Lastly, I challenge any batch script expert to optimize this script even further and post back the results for batch people to test.

Thanks, P


Try with this code in other words. You could use as a script subroutine or use this with the CALL and parameters functions to pass back to the original batch file:

:: Pass 1st parameter as number of days (whole numbers) to subtract from current day in   date
:: This script is able to subtract days to any date of the current date
:: This script will check for leap years, etc. as well
@echo on
::for /f "tokens=2-4 delims=/ " %%A in ("%date%") do set "mm=%%A" do & set "dd=%%B" do & set "yyyy=%%C"
set "mm=%date:~4,2%" & set "dd=%date:~7,2%" & set "yyyy=%date:~10,4%"
set CurDate=%mm%/%dd%/%yyyy%
set dayCnt=%1
if "%dayCnt%"=="" set dayCnt=1
:: Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100
:CHKDAY
if /I %dd% GTR 0 goto DONE
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
:: ** Month 12 falls through
:SET31
set /A dd=31 + %dd%
goto CHKDAY
:SET30
set /A dd=30 + %dd%
goto CHKDAY
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto CHKDAY
:SET29
set /A dd=29 + %dd%
goto CHKDAY
:DONE
if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%
echo Date %dayCnt% day(s) before %CurDate% is %mm%/%dd%/%yyyy%
SET DirDate=%mm%/%dd%/%yyyy%
:: The %2 parameter is passed from the calling script as the full path and name of the          file to call back
:: %2 equals %~fnx0
:: The dirdate variable is passed as parameter %1 back to the calling script
Call %2 %dirdate%
GOTO EOF

I'm going to look for a vb or something more efficient I can still incorporate or call from a batch to dynamically calculate dates.