Calculate business days using a batch file - date

I have a very simple batch file I am trying to write.
If today is 03/13, I would like my batch file to output:
"I will call you back on 03/15"
So it will take the date and ADD 2 business days. So if it were 03/15:
"I will call you back on 03/19"

Eh, do not worry, it can be done in batch. :) Here is an implementation of mine (~150 lines of code).
Example
https://gist.github.com/DavidRuhmann/4666270
Usage
Do something like this to adjust for the weekends.
if "%Date:~0,3%"=="Thu" call :DaysAhead 4
if "%Date:~0,3%"=="Fri" call :DaysAhead 4
if "%Date:~0,3%"=="Sat" call :DaysAhead 3
if "%Date:~0,3%"=="Sun" call :DaysAhead 2
if "%Date:~0,3%"=="Mon" call :DaysAhead 2
if "%Date:~0,3%"=="Tue" call :DaysAhead 2
if "%Date:~0,3%"=="Wed" call :DaysAhead 2

Use JScript to calculate the date and you're golden.
#if (#X)==(#Y) #end /* (batch + jscript hybrid script init)
:: *** Batch script *****
#echo off
setlocal
for /f %%I in ('cscript /nologo /e:jscript "%~f0"') do (
echo I will call you back on %%I
)
goto :EOF
:: *** JScript script *****/
var dow = new Date().getDay();
var days = (dow > 4) ? 9 - dow : (dow == 4 ? 4 : 2);
var d = new Date(new Date().getTime() + (1000 * 60 * 60 * 24) * days);
WScript.echo((d.getMonth() + 1) + '/' + d.getDate());
If today is Thursday, the script will return the following Monday. Friday through Sunday, the following Tuesday. Monday through Wednesday, two days ahead. And you don't have to worry about locale, leap year, leap frogs, lunar cycles, etc.

The Batch file below do what you want:
#echo off
rem AddBusinessDays.bat date numOfDays
rem Antonio Perez Ayala
rem Convert the date to Julian Day Number + number of days
for /F "tokens=1-3 delims=/" %%a in ("%1") do (
set /A mm=10%%a %% 100, dd=10%%b %% 100, yy=%%c
)
set /A a=mm-14, jd=(1461*(yy+4800+a/12))/4+(367*(mm-2-12*(a/12)))/12-(3*((yy+4900+a/12)/100))/4+dd-32075+2+%2, dow=jd%%7
rem Adjust Julian Day Number to avoid weekends
if %dow% lss 2 set /A jd+=2-dow
rem Convert Julian Day Number back to date
set /A l=jd+68569-2,n=(4*l)/146097,l=l-(146097*n+3)/4,i=(4000*(l+1))/1461001,l=l-(1461*i)/4+31,j=(80*l)/2447,dd=l-(2447*j)/80,l=j/11,mm=j+2-(12*l),yy=100*(n-49)+i+l
rem Assemble the result
if %dd% lss 10 set dd=0%dd%
if %mm% lss 10 set mm=0%mm%
set newDate=%mm%/%dd%/%yy%
echo %newDate%
Reference: http://www.hermetic.ch/cal_stud/jdn.htm#comp
For example:
>echo %date%
03/13/2013
>AddBusinessDays.bat %date% 2
03/15/2013
>AddBusinessDays.bat %date% 3
03/18/2013
>AddBusinessDays.bat %date% 4
03/18/2013
>AddBusinessDays.bat %date% 5
03/18/2013
>AddBusinessDays.bat %date% 6
03/19/2013
Antonio
PS - Yes, I know that this method will not work for everyone in the world. The good news are that I not wrote this solution for they all, but precisely for the OP although it is very easy to modify it for every computer. For example, previous program does NOT work in my computer because my locale is DD/MM/YYYY, but I can interchange dd and mm in two lines of previous program and I am pretty sure that most people in this world are also capable to do so! ;-)
Hi Antonio,
Just today I found that the code you shared didn't work for more than 7 days ahead, I changed some thing and now it works ever.
#echo off
rem AddBusinessDays.bat date numOfDays
rem adapted by Leonardo Contreras based on Antonio Perez Ayala with handling for more than 7 days
rem to convert Dow mm/dd/yyyy to mm/dd/yy
set mydate=%date:~4,2%/%date:~7,2%/%date:~10,4%
rem Convert the date to Julian Day Number + number of days
for /F "tokens=1-3 delims=/" %%a in ("%mydate%") do (
set /A mm=10%%a %% 100, dd=10%%b %% 100, yy=%%c
)
rem dow_orig is based on a 0-6 days statrting on Monday
set /A a=mm-14, jd_orig = (1461*(yy+4800+a/12))/4+(367*(mm-2-12*(a/12)))/12-(3*((yy+4900+a/12)/100))/4+dd-32075, dow_orig=jd_orig%%7
rem calculate new julian's day
set /A numw = (dow_orig+%3)/5, njd = jd_orig+%3+numw*2, dow=(njd)%%7
rem Adjust Julian Day Number to avoid weekends
if %dow% gtr 5 (set /A jd+=2 )
rem Convert Julian Day Number back to date
set /A l=njd+68569,n=(4*l)/146097,l=l-(146097*n+3)/4,i=(4000*(l+1))/1461001,l=l-(1461*i)/4+31,j=(80*l)/2447,dd=l-(2447*j)/80,l=j/11,mm=j+2-(12*l),yy=100*(n-49)+i+l
rem Assemble the result
if %dd% lss 10 set dd=0%dd%
if %mm% lss 10 set mm=0%mm%
set newDate=%mm%/%dd%/%yy%
echo %newDate%

Related

File has been modified in the last 15 mins -Batch Script

Hi I need help as I'm new to BatchScript.
I need to check if any file/folder within a directory has been modified in the last 15 mins.
Here's my logic :
Find last modified date
Find current date
Find if difference between these two is 15 mins.
I'm able to do the 1st 2 steps.I'm stuck with the third
Please help me to find the time difference between these 2 dates.
Or if there's a better/easier logic.
Here is my code:
#echo off
for /f %a in (' dir "D:\BatchFiles" /od/b/s/t') do set Date1= %~ta
echo The most recently created file is %Date1%
#echo off
for /f "delims=" %i in ('time /t') do set output=%i
#echo off
SET Date2= %DATE:~4,2%/%DATE:~7,2%/%DATE:~10,4% %output%
echo The current date is %Date2%
PAUSE
Here is a pure batch file that returns all files in a given directory of a given age, with the following restrictions:
dates are not resolved correctly, so if a file has been modified in the previous month, it might not be included in the result erroneously; in case the maximum age is to be defined in terms of days, a forfiles solution might be more reasonable;
files that have both characters ) and , in their paths will be missing in the output; this is because of a design flaw of the wmic command, which is used to retrieve locale-independent date/time information of the last modification of files;
To use the script -- let us call it max-aged-files.bat --, provide command line arguments like this:
max-aged-files.bat 15*60 "D:\BatchFiles"
The first argument is the maximal age of a file in terms of seconds; simple arithmetic expressions like 15*60 are understood. The second argument is the location and/or file pattern to apply for searching files; you can state a directory path like "D:\BatchFiles" here, or a file pattern like "*.bat", or a comination like "D:\BatchFiles\*.bat"; it you omit it, the current directory is used.
Here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* Please regard that this script cannot handle dates correctly!
rem so if current date and file date are in different months it fails! */
rem // Retrieve and prepare arguments:
set "MAXAGE=%~1" & rem // (maximum age of files in terms of seconds)
if defined MAXAGE (set /A "MAXAGE=%MAXAGE%+0") else (
>&2 echo ERROR: maximum age not specified! & exit /B 1
)
if %MAXAGE% GEQ 86400 (>&2 echo ERROR: maximum age exceeds range! & exit /B 1)
shift /1
set "LOCATION=%~1"
set "ATTR=%~a1"
set "ATTR=%ATTR:~,1%"
if not defined LOCATION (set "LOCATION=.\*.*") else (
if "%ATTR%"=="d" set "LOCATION=%LOCATION%\*.*"
)
rem /* Gather current date/time in standardised format
rem [like: `YYYYMMDDHHMMSS.UUUUUU+ZZZ`]: */
for /F "delims=" %%I in ('wmic OS GET LocalDateTime') do (
for /F "delims=" %%J in ("%%I") do set "CURRTIME=%%J"
)
rem // Extract `YYYYMMSS` portion from current date/time:
set "CURRDATE=%CURRTIME:~,8%"
rem // Extract `HHMMSS` portion from current date/time only:
for /F "delims=." %%T in ("%CURRTIME:~8%") do (
set "CURRTIME=%%T"
)
rem // Loop through all files at given location:
for %%F in ("%LOCATION%") do (
set "ITEM=%%~fF"
setlocal EnableDelayedExpansion
rem // Gather file date/time in standardised format:
for /F "delims=" %%E in ('
2^> nul wmic DataFile WHERE Name^="!ITEM:\=\\!" GET LastModified ^|^| ^
2^> nul wmic DataFile WHERE ^(Name^="!ITEM:\=\\!"^) GET LastModified
') do (
for /F "delims=" %%F in ("%%E") do set "FILETIME=%%F"
)
rem // Extract `YYYYMMSS` portion from file date/time:
set "FILEDATE=!FILETIME:~,8!"
rem // Extract `HHMMSS` portion from file date/time:
for /F "delims=." %%T in ("!FILETIME:~8!") do (
set "FILETIME=%%T"
)
rem // Compute date difference between file and current date:
set /A "DATEDIFF=CURRDATE-FILEDATE"
rem // Continue processing only if date difference is zero or one:
if !DATEDIFF! GEQ 0 if !DATEDIFF! LEQ 1 (
rem // Convert date difference to seconds:
set /A "DATEDIFF*=240000"
rem // Compute time difference, regarding also date difference:
set /A "TIMEDIFF=DATEDIFF+1!CURRTIME!-1!FILETIME!"
rem // Pad time difference to consist of 6 digits [like `HHMMSS`]:
set "TIMEDIFF=000000!TIMEDIFF!" & set "TIMEDIFF=!TIMEDIFF:~-6!"
rem // Convert time difference to seconds:
set /A "TIMEDIFF=1!TIMEDIFF:~-2!-100+60*(1!TIMEDIFF:~-4,-2!-100+60*(1!TIMEDIFF:~-6,-4!-100))"
rem // Return item if
if !TIMEDIFF! LEQ %MAXAGE% (
echo(!ITEM!
)
)
endlocal
)
endlocal
exit /B

Batch command - adding date at the end of folder

I currently run a batch command to create a folder 1 day in advanced and label it as MMDDYY.
Everything is working as intended except single digit days. Currently it named the next day folder has 12214, is it possible to have it name it as 120214?
#echo off
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%"
:loop
set /a DD+=1
if %DD% gtr 31 (
set DD=1
set /a MM+=1
if %MM% gtr 12 (
set MM=1
set /a YY+=1
set /a YYYY+=1
)
)
xcopy /d:%MM%-%DD%-%YYYY% /l . .. >nul 2>&1 || goto loop
echo %DD%/%MM%/%YYYY%
mkdir "C:\Users\Name\Desktop\%mm%%dd%%yy%\"
pause
You need to pad again the data once the operations have been done. Also you will need some more logic to handle the month change
#echo off
setlocal enableextensions disabledelayedexpansion
rem Retrieve data
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%"
rem Remove padding from date elements and increase day
set /a "y=%YYYY%", "m=100%MM% %% 100", "d=(100%DD% %% 100)+1"
rem Calculate month length
set /a "ml=30+((m+m/8) %% 2)" & if %m% equ 2 set /a "ml=ml-2+(3-y %% 4)/3-(99-y %% 100)/99+(399-y %% 400)/399"
rem Adjust day / month / year for tomorrow date
if %d% gtr %ml% set /a "d=1", "m=(m %% 12)+1", "y+=(%m%/12)"
rem Pad date elements and translate again to original variables
set /a "m+=100", "d+=100"
set "YYYY=%y%"
set "YY=%y:~-2%"
set "MM=%m:~-2%"
set "DD=%d:~-2%"
echo Tomorrow: %YYYY% / %MM% / %DD%
Just add the folder creation in the required format
Batch is cumbersome with date math. Leap years, month / year changes / etc can be a pain to deal with. I suggest using a JScript Date() object, where all such conversions are handled automatically.
As follows is a batch / JScript hybrid script. Save it with a .bat extension and run it as you are used to running your typical batch scripts.
#if (#a==#b) #end /* JScript ignores this multiline comment
:: batch portion
#echo off
setlocal
for /f "tokens=1-3" %%I in ('cscript /nologo /e:JScript "%~f0"') do (
set "MM=%%I"
set "DD=%%J"
set "YYYY=%%K"
)
xcopy /d:%MM%-%DD%-%YYYY% /l . .. >nul 2>&1 || goto loop
echo %MM%/%DD%/%YYYY%
mkdir "%userprofile%\Desktop\%MM%%DD%%YYYY:~-2%\"
pause
goto :EOF
:: end batch portion / begin JScript */
function zeroPad(what) { return (what+'').length < 2 ? '0'+what : what; }
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
WSH.Echo([
zeroPad(tomorrow.getMonth() + 1),
zeroPad(tomorrow.getDate()),
tomorrow.getFullYear()
].join(' '));

How to change variable in commnd prompt numerically

I have used system date from %date% using this code
set d=20%date:~6,2%%date:~0,2%
Its output is say 201309
How can I get the same for date of 30 days back(so I want 201308)? like is there any operation like addition/substraction for dates? I tried
set /a "date2=%date%-30"
But it gives error :"Invalid number. Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021)." as cmd asumes a value is hexadecimal if it starts with 0.
Using this batch file you should get what you need:
The routines can do some extra date math - the batch file is after the first 9 lines and can be self contained.
#echo off
call datebatch today -30
set "var=%day:0,6%"
echo "%var%"
pause
goto :eof
:datebatch
:: Date foward & backward
#echo off
if "%~2"=="" (
echo to get todays date use call "%~n0" today 0
echo to get yesterdays date use call "%~n0" today -1
echo to get 25 days before 19441213 call "%~n0" 1944/12/13 -25
echo to get 1250 days in the future call "%~n0" today 1250
echo.
echo Add a third parameter if you want a separator in the date string
echo EG: for this format YYYY-MM-DD using today's date
echo call "%~n0" today 0 -
echo.
pause
goto :EOF)
set date1=%1
set qty=%2
set separator=%~3
if /i "%date1%" EQU "TODAY" (set date1=now) else (set date1="%date1%")
echo >"%temp%\%~n0.vbs" s=DateAdd("d",%qty%,%date1%)
echo>>"%temp%\%~n0.vbs" WScript.Echo year(s)^&_
echo>>"%temp%\%~n0.vbs" right(100+month(s),2)^&_
echo>>"%temp%\%~n0.vbs" right(100+day(s),2)
for /f %%a in ('cscript //nologo "%temp%\%~n0.vbs"') do set result=%%a
del "%temp%\%~n0.vbs"
endlocal& set "YY=%result:~0,4%"&set "MM=%result:~4,2%"&set "DD=%result:~6,2%"
set "day=%YY%%separator%%MM%%separator%%DD%"
echo %%day%% is set to "%day%" (without the quotes)
echo %%YY%% is set to %YY%
echo %%MM%% is set to %MM%
echo %%DD%% is set to %DD%

Tomorrows date with leading zeros?

I'm looking to have a method of printing tomorrows date in a DD/MM/YYYY format. I'm currently running the following set of cmds:
#echo off
set /a d=%date:~0,2%
set /a m=%date:~3,2%
set /a y=%date:~6,4%
:loop
set /a d+=1
if %d% gtr 31 (
set d=1
set /a m+=1
if %m% gtr 12 (
set m=1
set /a y+=1
)
)
xcopy /d:%m%-%d%-%y% /h /l "%~f0" "%~f0\" >nul 2>&1 || goto loop
echo The date tomorrow is "%d%/%m%/%y%".
pause
The above works nicely, printing "The date tomorrow is "8/12/2012". However, I need both my DAY and MONTH values to come out with leading zeros when less than 10. I can't appear to figure out how this can be done. Could anyone help me?
Cheers,
EL
Your grabbing the wrong information for the sets for day/month/year.
Here are the correct sets
set /a d=%date:~7,2%
set /a m=%date:~4,2%
set /a y=%date:~10,4%
you should be able to easily figure out what variables go where by the following:
#echo off
:testing
set /a a=%date:~0,1%
set /a b=%date:~1,1%
set /a c=%date:~2,1%
set /a d=%date:~3,1%
set /a e=%date:~4,1%
set /a f=%date:~5,1%
set /a g=%date:~6,1%
set /a h=date:~7,1%
set /a i=%date:~8,1%
set /a j=%date:~9,1%
set /a k=%date:~10,1%
set /a l=%date:~11,1%
set /a m=%date:~12,1%
set /a n=%date:~13,1%
echo.%a%-a
echo.%b%-b
echo.%c%-c
echo.%d%-d
echo.%e%-e
echo.%f%-f
echo.%g%-g
echo.%h%-h
echo.%i%-i
echo.%j%-j
echo.%k%-k
echo.%l%-l
echo.%m%-m
echo.%n%-n
then when you get the first value you want it will be
set /a var=%date:~NUM1,NUM2%
Where NUM1 is the start NUM2 is how many characters to move to the right and VAR is the variable you want to set it to.
Alternatively using FOR statements might work better.
I saw that someone had mentioned that the user might be from EU or British. If that is the case their date setup would be (using FOR):
#ECHO OFF
FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/" %%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ " %%A IN ('echo %CDATE%') DO SET yyyy=%%B
set day=%dd%
set /a day+=01
SET date=%day%/%mm%/%yyyy%
echo.%date%
pause
Opps. I think I've just fixed my own problem by adding:
IF 1%d% LSS 100 SET d=0%d%
IF 1%m% LSS 100 SET m=0%m%
Before xcopy. So it should now read:
#echo off
set /a d=%date:~0,2%
set /a m=%date:~3,2%
set /a y=%date:~6,4%
:loop
set /a d+=1
if %d% gtr 31 (
set d=1
set /a m+=1
if %m% gtr 12 (
set m=1
set /a y+=1
)
)
IF 1%d% LSS 100 SET d=0%d%
IF 1%m% LSS 100 SET m=0%m%
xcopy /d:%m%-%d%-%y% /h /l "%~f0" "%~f0\" >nul 2>&1 || goto loop
echo The date tomorrow is "%d%/%m%/%y%".
pause
Hope that helps anyone with a similar issue :)
I tested your code... it did not work
Here is a proper portion of batch code that will work for what you need.
:getdate
set /a day=%date:~7,2%
IF %day% LSS 10 set day=0%day%
rem echo.The day is - %day%
set /a month=%date:~4,2%
IF %month% LSS 10 set month=0%month%
rem echo.The month is - %month%
set /a year=%date:~10,4%
rem echo.The year is - %year%
REM Setting Month / Days
set jan=31
set feb=28
set mar=31
set apr=30
set may=31
set jun=30
set jul=31
set aug=31
set sep=30
set oct=31
set nov=30
set dec=31
REM If Months are # set Month to Days
IF %month% EQU 1 set mon=%jan%
IF %month% EQU 2 set mon=%feb%
IF %month% EQU 3 set mon=%mar%
IF %month% EQU 4 set mon=%apr%
IF %month% EQU 5 set mon=%may%
IF %month% EQU 6 set mon=%jun%
IF %month% EQU 7 set mon=%jul%
IF %month% EQU 8 set mon=%aug%
IF %month% EQU 9 set mon=%sep%
IF %month% EQU 10 set mon=%oct%
IF %month% EQU 11 set mon=%nov%
IF %month% EQU 12 set mon=%dec%
echo.Today's Date is %month%/%day%/%year%
set /a day+=1
if %day% GTR %mon% set /a month+=1
if %day% GTR %mon% set day=1
IF %day% LSS 10 set day=0%day%
IF %month% GTR 12 set month=1& set /a year+=1
IF %month% LSS 10 set month=0%month%
echo.Tomorrow's Date is %month%/%day%/%year%
This will set the days in a month (except leap years) and should solve any problems you have, assuming you don't know this yet, but if a month only has 30 days your current code will set the day to 31, regardless if it's say Feburary and there are only 28 days.
You will have to insert your other code into here, as I'm not sure what your loop is doing, otherwise I just changed the d = day, m = month and y = year (mon is comparing the days in the month).
Good luck, HTH

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.
Found this script on ss64.com: https://ss64.com/nt/syntax-datemath.html (license: https://ss64.com/docs/copyright.html)
You can keep it separate and call it from your batch files without cluttering your code, it will fill some environments variables with the operation result.
For example, this will subtract one day to the current date (on my system date is returned in the "dd/mm/yyyy" format):
set YY=%date:~-4,4%
set MM=%date:~-7,2%
set DD=%date:~-10,2
call datemath.bat %YY% %MM% %DD% - 1
echo year=%_yy_int%, month=%_mm_int%, day=%_dd_int%
echo padded date:%_ymd_str%, padded month:%_mm_str%, padded day:%_dd_str%
The script:
#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 YY MM DD - YY2 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 YY 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:
echo ___________________________________
pause
echo:
echo:
echo CALL DateMath YY MM DD
echo:
echo Will set the following variables:
echo _ymd_str, _yy_int
echo _mm_str, _mm_int,
echo _dd_str, _dd_int
echo:
echo ___________________________________
echo:
echo _ymd_str is in YYYYMMDD format.
echo:
echo _yy_int is in YYYY format, even if YY format was originally supplied.
echo This conversion is useful for FAT/NTFS file dates which are in YY format.
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%
Can be done with adding jscript code to a batch file.
Here's the dayAdder.bat that accepts only one argument - the days you want to add to the current date and prints the result:
#if (#X) == (#Y) #end /* JScript comment
#echo off
cscript //E:JScript //nologo "%~f0" %*
exit /b %errorlevel%
#if (#X)==(#Y) #end JScript comment */
var days=parseInt(WScript.Arguments.Item(0));
Date.prototype.addDays = function(days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}
var date = new Date();
WScript.Echo(date.addDays(5));
WScript.Echo("Year: " + date.getFullYear());
WScript.Echo("Month: " + date.getMonth());
WScript.Echo("DayOfTeWEek: " + date.getDay());
examaple and output:
E:\scripts>dayAdder.bat 7
Sun Nov 8 16:27:48 UTC+0200 2020
Year: 2020
Month: 10
DayOfTeWEek: 2
DayOfTheMonth: 3
You can modify it in way that will be suitable for you.