Here is two code options. I am using functions in both to get the current date and time. If you don't need that you can remove that.
This is the fastest of the two options. It converts the date to a Julian date to do the math, then converts it back to a normal date.
@echo off
setlocal
REM Get the current date
REM Will return variables YY, YYYY, MM, DD, HH, Min and Sec
Call :GetDateTime
REM Add or Subtract from the current date
REM Must use + or - symbol
REM Revised date will be assigned to RetVar
REM LeapDay
Call :AddSubDate 2016 03 01 -1 LeapDay
REM Yesterday
Call :AddSubDate %YYYY% %MM% %DD% -2 past
REM Tomorrow
Call :AddSubDate %YYYY% %MM% %DD% +2 future
echo LeapDay : %LeapDay%
echo Past : %past%
echo Today : %YYYY%%MM%%DD%
echo Future : %future%
pause
GOTO :EOF
:AddSubDate Year Month Day <+/-Days> RetVar
setlocal & set a=%4
set "yy=%~1"&set "mm=%~2"&set "dd=%~3"
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
if %yy% LSS 100 set /a yy+=2000 &rem Adds 2000 to two digit years
set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
if %a:~0,1% equ + (set /a JD=%JD%+%a:~1%) else set /a JD=%JD%-%a:~1%
set /a L= %JD%+68569, N= 4*L/146097, L= L-(146097*N+3)/4, I= 4000*(L+1)/1461001
set /a L= L-1461*I/4+31, J= 80*L/2447, K= L-2447*J/80, L= J/11
set /a J= J+2-12*L, I= 100*(N-49)+I+L
set /a YYYY= I, MM=100+J, DD=100+K
set MM=%MM:~-2% & set DD=%DD:~-2%
set ret=%YYYY: =%%MM: =%%DD: =%
endlocal & set %~5=%ret%
exit /b
:GetDateTime Year Month Day Hour Minute Second
@echo off & setlocal
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%"
( ENDLOCAL
set "YY=%YY%"
set "YYYY=%YYYY%"
set "MM=%MM%"
set "DD=%DD%"
set "HH=%HH%"
set "Min=%Min%"
set "Sec=%Sec%"
)
exit /b
The second option uses a trick with the xcopy command to check if the date is a valid date. So it is technically not doing any date math like the previous solution which is converting to the Julian date to do that date math. This option only does subtraction. The first option can add or subtract.
@echo off
setlocal
REM set the number of days to substract
SET DAYS=180
REM Call function to check if the date is valid.
CALL :validdate "%days%" subdate
echo Old date: %subdate%
pause
endlocal
GOTO :EOF
:validdate
setlocal
set "day=%~1"
set rand=%random%
md "%temp%\dummy%rand%\empty%rand%"
REM Get todays date
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
REM set year month and day into its own variables.
set /a y=%dt:~0,4%
set /a m=1%dt:~4,2%
set /a d=1%dt:~6,2%
:loop
if "%day%"=="0" (
rd /s /q "%temp%\dummy%rand%"
endlocal &set "%~2=%y%%m:~-2%%d:~-2%"
GOTO :EOF
)
set /a d-=1
if %d% lss 101 (
set d=131
set /a m-=1
if %m% lss 101 (
set m=112
set /a y-=1
)
)
xcopy /d:%m:~-2%-%d:~-2%-%y% /t "%temp%\dummy%rand%\empty%rand%" "%temp%\dummy%rand%" >nul 2>&1 && (set /a day-=1 & goto loop) || goto loop
GOTO :EOF