(view source code of dateadd.bat as plain text)
@ECHO OFF
ECHO.
:: Reset variables
SET "cDate="
SET "iDate="
SET "sDate="
:: Check the Windows version
IF NOT "%OS%"=="Windows_NT" GOTO Syntax
SETLOCAL ENABLEDELAYEDEXPANSION
:: Initialize variable
SET "Error=0"
:: Check the command line arguments
IF "%~1"=="" GOTO Syntax
IF NOT "%~3"=="" GOTO Syntax
ECHO.%* | FINDSTR.EXE /R /I /C:"[^-\""adnotwy/0-9 ]" >NUL && GOTO Syntax
:: Get today's date in local date format
SET ArgsCount=0
FOR %%A IN (%Date%) DO (
SET /A ArgsCount += 1
SET "Today=%%~A"
)
IF %ArgsCount% GTR 2 (
REM Use WMIC to get today's date in ISO 8601 format
FOR /F "skip=1 tokens=1-3" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Month^,Year /Format:table') DO (
IF NOT "%%~F"=="" (
SET Today=%%C-%%B-%%A
)
)
)
IF "%~2"=="" (
SET "cDate=%Today%"
SET /A "cDays=%~1" >NUL 2>&1
) ELSE (
SET "cDate=%~1"
IF /I "%~1"=="Now" (SET "cDate=%Today%")
IF /I "%~1"=="Today" (SET "cDate=%Today%")
SET /A "cDays=%~2" >NUL 2>&1
)
IF "%cDays%"=="0" (
ECHO.
ECHO Error: %cDays% is not a valid integer
GOTO Syntax
)
:: Read the Date format from the registry; if this fails, we're probably dealing with an older Windows version
FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v iDate 2^>NUL') DO SET "iDate=%%~A"
FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v sDate 2^>NUL') DO SET "sDate=%%~A"
IF "%iDate%"=="" GOTO Syntax
:: Check if a valid date in local format was specified
ECHO.%cDate% | FINDSTR.EXE /R /B /C:"[0-9][0-9]*%sDate%[0-9][0-9]*%sDate%[0-9][0-9][0-9][0-9]" >NUL
IF ERRORLEVEL 1 (
REM Try testing for ISO 8601 format
ECHO.%cDate% | FINDSTR.EXE /R /B /C:"[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" >NUL
IF ERRORLEVEL 1 (
ECHO.
ECHO Error: %cDate% is not a valid date
GOTO Syntax
) ELSE (
SET "iDate=2"
SET "sDate=-"
)
)
:: Parse the date specified, abort on failure
CALL :ParseDate %cDate%
IF "%Error%"=="1" GOTO Syntax
:: Convert the parsed Gregorian date to Julian
CALL :JDate %GYear% %GMonth% %GDay%
:: Display original input
ECHO Starting date : %cDate%
:: Add or subtract the specified number of days
IF "%cDays:~0,1%"=="-" (
SET /A "NewJDate = %JDate% - %cDays:~1%"
ECHO Days subtracted : %cDays:~1%
) ELSE (
SET /A "NewJDate = %JDate% + %cDays%"
ECHO Days added : %cDays%
)
:: Convert the new Julian date back to Gregorian again
CALL :GDate %NewJDate%
:: Reformat the date to local format
CALL :ReformatDate %GDate%
:: Display the result
ECHO Resulting date : %LDate%
:: Return the result in a variable named after this batch file
ENDLOCAL & SET "%~n0=%LDate%"
GOTO:EOF
::===================================::
:: ::
:: - S u b r o u t i n e s - ::
:: ::
::===================================::
:GDate
:: Convert Julian date back to "normal" Gregorian date
:: Argument : Julian date
:: Returns : YYYY MM DD
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
::
SET /A "P = %~1 + 68569"
SET /A "Q = 4 * %P% / 146097"
SET /A "R = %P% - ( 146097 * %Q% + 3 ) / 4"
SET /A "S = 4000 * ( %R% + 1 ) / 1461001"
SET /A "T = %R% - 1461 * %S% / 4 + 31"
SET /A "U = 80 * %T% / 2447"
SET /A "V = %U% / 11"
SET /A "GYear = 100 * ( %Q% - 49 ) + %S% + %V%"
SET /A "GMonth = %U% + 2 - 12 * %V%"
SET /A "GDay = %T% - 2447 * %U% / 80"
:: Clean up the mess
FOR %%A IN (P Q R S T U V) DO SET "%%~A="
:: Add leading zeroes
IF 1%GMonth% LSS 20 SET "GMonth=0%GMonth%"
IF 1%GDay% LSS 20 SET "GDay=0%GDay%"
:: Return value
SET "GDate=%GYear% %GMonth% %GDay%"
GOTO:EOF
:JDate
:: Convert date to Julian
:: Arguments : YYYY MM DD
:: Returns : Julian date
::
:: First strip leading zeroes
SET "MM=%2"
SET "DD=%3"
IF "%MM:~0,1%"=="0" SET "MM=%MM:~1%"
IF "%DD:~0,1%"=="0" SET "DD=%DD:~1%"
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
SET /A "Month1 = ( %MM% - 14 ) / 12"
SET /A "Year1 = %~1 + 4800"
SET /A "JDate = 1461 * ( %Year1% + %Month1% ) / 4 + 367 * ( %MM% - 2 -12 * %Month1% ) / 12 - ( 3 * ( ( %Year1% + %Month1% + 100 ) / 100 ) ) / 4 + %DD% - 32075"
FOR %%A IN (Month1 Year1) DO SET "%%~A="
GOTO:EOF
:ParseDate
:: Parse (Gregorian) date depending on registry's date format settings
:: Argument : Gregorian date in local date format, or in ISO 8601 format
:: Requires : sDate (local date separator), iDate (local date format number)
:: Returns : GYear (4-digit year), GMonth (2-digit month), GDay (2-digit day)
::
IF "%iDate%"=="0" FOR /F "tokens=1-3 delims=%sDate%" %%A IN ('ECHO.%1') DO (
SET "GYear=%%~C"
SET "GMonth=%%~A"
SET "GDay=%%~B"
)
IF "%iDate%"=="1" FOR /F "tokens=1-3 delims=%sDate%" %%A IN ('ECHO.%1') DO (
SET "GYear=%%~C"
SET "GMonth=%%~B"
SET "GDay=%%~A"
)
IF "%iDate%"=="2" FOR /F "TOKENS=1-3 DELIMS=%sDate%" %%A IN ('ECHO.%1') DO (
SET "GYear=%%~A"
SET "GMonth=%%~B"
SET "GDay=%%~C"
)
IF %GDay% GTR 31 SET "Error=1"
IF %GMonth% GTR 12 SET "Error=1"
GOTO:EOF
:ReformatDate
:: Reformat the date back to the local format
:: Arguments : YYYY MM DD
:: Returns : LDate (Gregorian date in local format)
::
IF "%iDate%"=="0" SET "LDate=%~2%sDate%%~3%sDate%%~1"
IF "%iDate%"=="1" SET "LDate=%~3%sDate%%~2%sDate%%~1"
IF "%iDate%"=="2" SET "LDate=%~1%sDate%%~2%sDate%%~3"
GOTO:EOF
:Syntax
ECHO.
ECHO DateAdd.bat, Version 2.02 for Windows XP Professional and later
ECHO Add the specified number of days to the specified date
ECHO.
ECHO Usage: DATEADD [ date ] days
ECHO.
ECHO Where: date is a "normal" Gregorian date, either in the local date
ECHO format, or in ISO 8601 yyyy-MM-dd format, or "Today"
ECHO or "Now" (default if not specified: today's date)
ECHO days is the number of days to add (negative to subtract)
ECHO.
ECHO E.g. DATEADD 2017-01-01 1 will return 2017-01-02
ECHO DATEADD 2017-01-01 -1 will return 2016-12-31
:: To show the following "advanced" examples, Windows XP or later is required
IF NOT "%OS%"=="Windows_NT" GOTO Skipped2
FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v iDate 2^>NUL') DO SET "iDate=%%~A"
FOR /F "tokens=3" %%A IN ('REG.EXE Query "HKEY_CURRENT_USER\Control Panel\International" /v sDate 2^>NUL') DO SET "sDate=%%~A"
:: Windows XP or later is required to read iDate, so if iDate isn't set, skip the "advanced" examples
IF "%iDate%"=="" GOTO Skipped2
FOR %%A IN (%Date%) DO SET "Today=%%~A"
CALL :ParseDate %Today%
IF NOT "%Error%"=="0" GOTO Skipped1
CALL :JDate %GYear% %GMonth% %GDay%
SET /A "NewJDate = %JDate% + 1"
CALL :GDate %NewJDate%
CALL :ReformatDate %GDate%
SET "Tomorrow=%LDate%"
CALL :ParseDate %Today%
CALL :JDate %GYear% %GMonth% %GDay%
SET /A "NewJDate = %JDate% - 1"
CALL :GDate %NewJDate%
CALL :ReformatDate %GDate%
SET "Yesterday=%LDate%"
:Skipped1
IF "%Yesterday%"=="" (
ECHO DATEADD %Today% 1 will return tomorrow's date ^(as will DATEADD 1^)
ECHO DATEADD %Today% -1 will return yesterday's date ^(as will DATEADD -1^)
) ELSE (
ECHO DATEADD %Today% 1 will return %Tomorrow%
ECHO DATEADD 1 will return %Tomorrow% too
ECHO DATEADD %Today% -1 will return %Yesterday%
ECHO DATEADD -1 will return %Yesterday% too
)
:: End of "advanced" examples section
:Skipped2
ECHO.
ECHO Notes: By default, the returned date will be presented in the local date
ECHO format; however, if the date in the command line argument is in the
ECHO ISO 8601 yyyy-MM-dd format, the result will be in ISO 8601 format too.
ECHO Unlike its earlier 1.* versions, this batch file does not require
ECHO elevated privileges.
ECHO.
ECHO Credits: Julian date conversion based on Fliegel-Van Flandern algorithms from
ECHO the Astronomical Almanac, provided by Doctor Fenton on the Math Forum
ECHO http://mathforum.org/library/drmath/view/51907.html
ECHO and converted to batch code by Ron Bakowski.
ECHO.
ECHO Written by Rob van der Woude
ECHO http://www.robvanderwoude.com
IF "%OS%"=="Windows_NT" ENDLOCAL
IF "%OS%"=="Windows_NT" EXIT /B 1
page last modified: 2024-04-16; loaded in 0.0076 seconds