How-to: Add or subtract days from any date - DateMath.cmd

To add or subtract days from any date, copy the script below or download here and save as DateMath.cmd

   @ECHO off
   SETLOCAL
   :: DateMath, a general purpose date math routine
   
   :: If DateMath detects an error, variable _dd_int is set to 999999.
   SET v_dd_int=0
   SET v_mm_int=0 
   SET v_yy_int=0
   SET v_ymd_str=
   SET v_mm_str=
   SET v_dd_str=
   
   IF "%3"=="" goto s_syntax
   IF "%4"=="+" goto s_validate_year
   IF "%4"=="-" goto s_validate_year
   IF "%4"=="" goto s_validate_year
   
   :s_syntax
   echo:
   echo DATEMATH SYNTAX:
   echo _______________
   echo:
   echo DateMath will set the variables as listed below
   echo 'str' variables include leading zeros e.g. "01"
   echo 'int' variables leading zeros are stripped e.g. "1"
   echo:
   echo CALL DateMath YYYY MM DD - YYYY2 MM2 DD2 
   echo:
   echo Will set variable _dd_int to the signed difference
   echo between the 2 dates (measured in days)
   echo:
   echo:
   echo CALL DateMath YYYY MM DD +/- Days 
   echo:
   echo Will set the following variables to the result of 
   echo adding or substracting days from the initial date:
   echo    _ymd_str, _yy_int
   echo    _mm_str, _mm_int,
   echo    _dd_str, _dd_int
   echo:
   echo _yy_int is in YYYY format, even if YY format was originally supplied.
   echo:

   ENDLOCAL & SET /a _dd_int=999999
   goto :eof

   :s_validate_year
   ::strip leading zeros
    SET v_yy=%1
    if %v_yy:~0,1% EQU 0 set v_yy=%v_yy:~1%

    :: Check for Y2K
    IF %v_yy% LSS 100 IF %v_yy% GEQ 80 SET /A v_yy += 1900
    IF %v_yy% LSS 80 SET /A v_yy += 2000
    
    :: at this point v_yy contains a 4 digit year

   ::validate month and day
    if %2 GTR 12 goto s_syntax
    if %3 GTR 31 goto s_syntax

    SET v_mm=%2
    SET v_dd=%3

    ::strip leading zeros
    if %v_mm:~0,1% EQU 0 set v_mm=%v_mm:~1%
    if %v_dd:~0,1% EQU 0 set v_dd=%v_dd:~1%

   :: Set the int variables
    SET /a v_dd_int=%v_dd%
    SET /a v_yy_int=%v_yy%
    SET /a v_mm_int=%v_mm%

   :: Determine which function to perform - ADD, SUBTRACT or CONVERT

    If not "%6"=="" goto s_validate_2nd_date 
    if "%4"=="" goto s_convert_only

   :: Add or subtract  days to a date
    SET /a v_number_of_days=%5
    goto s_add_or_subtract_days

   :s_convert_only

    SET /a v_dd_int=%v_dd%
    IF %v_dd% LEQ 9 (SET v_dd_str=0%v_dd%) ELSE (SET v_dd_str=%v_dd%)
    IF %v_mm% LEQ 9 (SET v_mm_str=0%v_mm%) ELSE (SET v_mm_str=%v_mm%)
    SET v_ymd_str=%v_yy%%v_mm_str%%v_dd_str%

   ECHO DATEMATH - Convert date only (no maths)
   goto s_end
   ::::::::::::::::::::::::::::::::::::::::::::::::::
   
   :s_validate_2nd_date
    If "%4"=="+" goto s_syntax
    :: Subtracting one date from another ::::::
    :: strip leading zero
    SET v_yy2=%5
    if %v_yy2:~0,1% EQU 0 set v_yy2=%v_yy2:~1%

    if %v_yy2% GTR 99 goto s_validate2nd_month
    if %v_yy2% GTR 49 goto s_prefix_2_1950_1999
    if %v_yy2% LSS 10 goto s_prefix_2_2000_2009
    SET v_yy2=20%v_yy2%
    goto s_validate2nd_month

   :s_prefix_2_2000_2009
    SET v_yy2=200%v_yy2%
    goto s_validate2nd_month

   :s_prefix_2_1950_1999
    SET v_yy2=19%v_yy2%

   :s_validate2nd_month
    ::strip leading zeros
    ::SET /a v_yy2=%v_yy2%
    if %v_yy2:~0,1% EQU 0 set v_yy2=%v_yy2:~1%
    ::v_yy2 now contains a 4 digit year

    if %6 GTR 12 goto s_syntax
    SET v_mm2=%6

    if %7 GTR 31 goto s_syntax
    SET v_dd2=%7

    ::strip leading zeros
    ::SET /a v_mm2=%v_mm2%
    if %v_mm2:~0,1% EQU 0 set v_mm2=%v_mm2:~1%
    ::SET /a v_dd2=%v_dd2%
    if %v_dd2:~0,1% EQU 0 set v_dd2=%v_dd2:~1%

   call :s_julian_day %v_yy_int% %v_mm_int% %v_dd_int%
   SET v_sumdays1=%v_JulianDay%

   call :s_julian_day %v_yy2% %v_mm2% %v_dd2%
   SET v_sumdays2=%v_JulianDay%
   
   SET /a v_dd_int=%v_sumdays1% - %v_sumdays2%
   
   ECHO DATEMATH - Subtracting one date from another = days difference
   ECHO ~~~~~~
   ECHO %v_dd_int%
   ECHO ~~~~~~
   goto s_end_days
   ::::::::::::::::::::::::::::::::::::::::::::::::::
   
   :s_add_or_subtract_days
   if /i "%4"=="+" goto s_add_up_days

   :: Subtract all days ::::::
   SET /a v_dd=%v_dd% - %v_number_of_days%
   
   :s_adjust_month_year
   if %v_dd% GEQ 1 goto s_add_subtract_days_DONE
   SET /a v_mm=%v_mm% - 1
   if %v_mm% GEQ 1 goto s_add_days_%v_mm%
   SET /a v_yy=%v_yy% - 1
   SET /a v_mm=%v_mm% + 12
   goto s_add_days_%v_mm%
   
   :s_add_days_2
   SET /a v_dd=%v_dd% + 28
   SET /a v_leapyear=%v_yy% / 4
   SET /a v_leapyear=%v_leapyear% * 4
   if %v_leapyear% NEQ %v_yy% goto s_adjust_month_year
   SET /a v_dd=%v_dd% + 1
   goto s_adjust_month_year
    
   :s_add_days_4
   :s_add_days_6
   :s_add_days_9
   :s_add_days_11
   SET /a v_dd=%v_dd% + 30
   goto s_adjust_month_year

   :s_add_days_1
   :s_add_days_3
   :s_add_days_5
   :s_add_days_7
   :s_add_days_8
   :s_add_days_10
   :s_add_days_12
   SET /a v_dd=%v_dd% + 31
   goto s_adjust_month_year
 
   :s_add_up_days
   :: add all days ::::::
   SET /a v_dd=%v_dd% + %v_number_of_days%
   
   :s_subtract_days_
   goto s_subtract_days_%v_mm%
     
   :s_adjust_mth_yr
   SET /a v_mm=%v_mm% + 1
   if %v_mm% LEQ 12 goto s_subtract_days_%v_mm%
   SET /a v_yy=%v_yy% + 1
   SET /a v_mm=%v_mm% - 12
   goto s_subtract_days_%v_mm%

   :s_subtract_days_2
   SET /a v_leapyear=%v_yy% / 4
   SET /a v_leapyear=%v_leapyear% * 4
   If %v_leapyear% EQU %v_yy% goto s_subtract_leapyear

   if %v_dd% LEQ 28 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 28
   goto s_adjust_mth_yr
   
   :s_subtract_leapyear
   if %v_dd% LEQ 29 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 29
   goto s_adjust_mth_yr
   
   :s_subtract_days_4
   :s_subtract_days_6
   :s_subtract_days_9
   :s_subtract_days_11
   if %v_dd% LEQ 30 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 30
   goto s_adjust_mth_yr

   :s_subtract_days_1
   :s_subtract_days_3
   :s_subtract_days_5
   :s_subtract_days_7
   :s_subtract_days_8
   :s_subtract_days_10
   :s_subtract_days_12
   if %v_dd% LEQ 31 goto s_add_subtract_days_DONE
   SET /a v_dd=%v_dd% - 31
   goto s_adjust_mth_yr
   
   :s_add_subtract_days_DONE
   SET /a v_dd_int=%v_dd%
   SET /a v_mm_int=%v_mm%
   SET /a v_yy_int=%v_yy%
   IF %v_dd% GTR 9 (SET v_dd_str=%v_dd%) ELSE (SET v_dd_str=0%v_dd%)
   IF %v_mm% GTR 9 (SET v_mm_str=%v_mm%) ELSE (SET v_mm_str=0%v_mm%)
   SET v_ymd_str=%v_yy%%v_mm_str%%v_dd_str%
   
   ECHO DATEMATH - add or subtract days from a date = new date
   goto s_end
   ::::::::::::::::::::::::::::::::::::::::::::::::::

   :s_julian_day
   SET v_year=%1
   SET v_month=%2
   SET v_day=%3
   
   SET /a v_month=v_month
   SET /a v_day=v_day
   
   SET /A a = 14 - v_month
   SET /A a /= 12
   SET /A y = v_year + 4800 - a
   SET /A m = v_month + 12 * a - 3
   SET /A m = 153 * m + 2
   SET /A m /= 5
   SET /A v_JulianDay = v_day + m + 365 * y + y / 4 - y / 100 + y / 400 - 32045
   
   ECHO The Julian Day is [%v_JulianDay%]
   goto :eof
   ::::::::::::::::::::::::::::::::::::::::::::::::::
   
   :s_end
   ECHO ~~~~~~~~~~~~
   ECHO [%v_ymd_str%] YY=[%v_yy_int%] MM=[%v_mm_str%] DD=[%v_dd_str%]
   ECHO ~~~~~~~~~~~~
   :s_end_days
   ENDLOCAL&SET /a _yy_int=%v_yy_int%&SET /a _mm_int=%v_mm_int%&SET /a _dd_int=%v_dd_int%&SET _ymd_str=%v_ymd_str%&SET _mm_str=%v_mm_str%&SET _dd_str=%v_dd_str%

In other languages, performing basic math on date values is much easier, PowerShell has .addDays, VBScript has DateAdd, both of which accept negative numbers for subtractions.

Examples

D:\> datemath 2021 05 08
DATEMATH - Convert date only (no maths)
~~~~~~~~~~~~
[20210508] YY=[2021] MM=[05] DD=[08]
~~~~~~~~~~~~

D:\> datemath 2027 12 01 - 2002 11 02
The Julian Day is [2461741]
The Julian Day is [2452581]
DATEMATH - Subtracting one date from another = days difference
~~~~~~
9160
~~~~~~

D:\> datemath 2002 11 02 + 9160
DATEMATH - add or subtract days from a date = new date
~~~~~~~~~~~~
[20271201] YY=[2027] MM=[12] DD=[01]
~~~~~~~~~~~~

D:\> datemath 2012 09 08 - 2011 09 08
The Julian Day is [2456179]
The Julian Day is [2455813]
DATEMATH - Subtracting one date from another = days difference
~~~~~~
366
~~~~~~

“We were having one of those great first dates you can only have when it’s not an actual date” ~ Sarah Jessica Parker

Related commands

tdiff.cmd - Calculate the difference in Hours/Mins between two time values.
SetLocal - Control the visibility of environment variables in a batch file.
How-to: PowerShell variables - these support Math operations out of the box (.addDays)
Rules for how CMD.EXE parses numbers - DosTips forum (Dave Benham).


 
Copyright © 1999-2024 SS64.com
Some rights reserved