Average timestamp in batch file - windows

so in short my script currently outputs a csv with the log name, time stamp (10:38:52) and the message (Verification: SUCCESS and SendResponse: Response message).
I now need for this script to be able to calculate and output the time difference between the time stamp on the first message and the timestamp on the second message and provide an average at the bottom of the csv.
#echo off
setlocal EnableDelayedExpansion
echo."Location","Date Time","Result","diff" > output2.csv
(
for %%a in (z:\logdir\*.log) do (
for /f "tokens=1,2,3,4,5,6,7,8,9,10 delims=[+]" %%B in ('findstr /g:searchstrings.txt ^< %%a') do (
set var=%%B
set var1=!var:~-6!
echo."%%a","!var1!","%%B","%%F","timetaken"
)
)
) >> output2.csv
the log file contains many entries but this script should and does pull out just the following lines
[20110314T103852][EMVLib][5056][I000000]: Verification: SUCCESS
[20110314T103902][CSV][3232][D000000]: SendResponse: Response message
These search strings are defined by file searchstrings.txt
Thanks for any help on this!

you have to parse the timestamp and calculate the time value in, say, seconds.
This code, assuming this format 20110314T103852 for the passed string in %1, returns the time value in %2
EDIT: I discovered that you cannot pass the string directly, so I have modified the code
:gettime
set hh=!%1:~9,2!
set mm=!%1:~11,2!
set ss=!%1:~13,2!
set /A %2=hh*3600+mm*60+ss
goto :eof
You may then use it to calculate the time difference like this
set t=%%a
call :gettime t t1
...
set t=%%a
call :gettime t t2
set /A deltat=t2-t1
for a more detailed description of the commands used here, check HELP SET and HELP CALL information.

The code of PA shows the idea, but as it's batch there is no simple solution :-)
The getTime function will fail for 14% of the timestamps of a day.
Why? Because batch handles all numbers with leading zeros as octals, so a 08 and a 09 isn't convert to 8 or 9, it simply fails.
There exists a workaround with prefix a 1 and use only the remainder.
set /a "hh=1!var:0,2! %% 100"
08 -> 108 mod 100 -> 8
So the complete batch could look like
#echo off
setlocal EnableDelayedExpansion
#echo off
setlocal EnableDelayedExpansion
echo."Location","Date Time","Result" > output2.csv
set totalVerifyTime=0
set totalVerifyCount=0
(
for %%a in (n.txt) do (
for /f "tokens=1,5 delims=[+]" %%B in (%%a) do (
set timefield=%%B
set timestamp=!timefield:~-6!
set /a "seconds=1!timestamp:~-2!%%100 + ( 1!timestamp:~0,2!%%100 * 60 + 1!timestamp:~2,2!%%100 ) * 60"
if "%%C"==": Verification: SUCCESS" (
set verifyStart=!seconds!
echo."%%a","!timestamp!","%%B","%%C", "!seconds!", "start of verify"
) ELSE (
set /a diff=seconds - verifyStart
echo."%%a","!timestamp!","%%B","%%C", "!seconds!", "!diff!"
set /a totalVerifyTime+=diff
set /a totalVerifyCount+=1
)
)
)
)
set /a "totalAvg=totalVerifyTime/totalVerifyCount"
echo avg = !totalAvg!

Related

CMD - Pivot / Transpose lines of file [e.g. convert 1500 lines (x1 col) --> 500 lines (x3 col)]

how please can I 'pivot' or transpose a file (i.e. turn a single-column list, into a table of data)...
Currently...
VideoA.name
VideoA.size
VideoA.bitrate
VideoB.name
VideoB.size
VideoB.bitrate
...
Desired...
VideoA.name, VideoA.size, VideoA.bitrate
VideoB.name, VideoB.size, VideoB.bitrate
Name
Size
Bitrate
VideoA.name
VideoA.size
VideoA.bitrate
VideoB.name
VideoB.size
VideoB.bitrate
Extra Info / Context
I'm aware people often ask 'why are you doing this?' so (if interested), here is the wider context / problem I am trying to solve...
I have a list of files in Files.txt
I have a jscript batch file getProps.bat that extract file properties and prints them, 1 per line
I have written a batch file to loop through Files.txt, get the properties of each and write the output to Details.csv
However if I have 500 files x 3 properties, this currently gives me 1500 lines, and I want 500 lines x 3 columns
GetProps_AllFiles.bat
---------------------
#ECHO OFF
SETLOCAL
FOR /F "tokens=*" %%A in (Files.txt) do (
getprops %%A 0,1,320 /noheaders >> Details.csv
)
Thanks in advance!
Use the "standard way" (for /f) to read a file line by line, extended by a counter. Add the line to a string (line), followed by a comma (or whatever you want to use as separator), and increase the counter. Except it's the third line. Then print the string plus the current line, reset the counter and string, and repeat.
#echo off
setlocal enabledelayedexpansion
set "line="
set count=0
(for /f "delims=" %%a in (test.txt) do (
set /a count+=1
if !count! equ 3 (
echo !line!%%a
set "line="
set count=0
) else (
set line=!line!%%a,
)
))>test.csv
The below is a slight adjustment to the code kindly provided by Stephan that allows a filename and number of lines to be passed into the script...
ColumiseFile.cmd
----------------
#ECHO OFF
SETLOCAL enabledelayedexpansion
REM :: USAGE -----------------------------------------------------------------
REM ColumiseFile [1]File.txt [2]NumOfLines
REM > Concatenates every n Lines into 1, exporting result to File.csv
SET "File=%1"
SET /A Lines=%2
REM :: MAIN -------------------------------------------------------------------
REM Thanks to Stephan [https://stackoverflow.com/a/67664755/15919675]
REM Loops through input file, compacting every n lines into 1
set "line="
set count=0
(for /f "delims=" %%a in (%File%) do (
set /a count+=1
if !count! equ %Lines% (
echo !line!%%a
set "line="
set count=0
) else (
set line=!line!%%a,
)
REM :: OUTPUT -----------------------------------------------------------------
REM Create .csv in same location as source .txt file
))>%~dpn1.csv

Ampersand was not expecting error while loading an array from a variable

I am new to batch scripting.I was trying with the tabcmd get command in the batch script.The url parameters are seperated by &.
eg:
set param=id=%%a^&name=%%b^&addr=%%c idno=%%a^&fullname=%%b^&address=%%c
I am getting %%a ,%%b,%c values from a csv file using for loop. But before that i need to load the the above param variable to an array like this
a[0]=id%%20num=%%a&name=%%b&addr=%%c a[1]=idno=%%a&fullname=%%b&address=%%c
below is the for loop i used
for %%a in (%param%) do (
set d[%p%]=%%a)
getting the error & was not expected at this time.
tried the below as well
setlocal enabledelayedexpansion
for %%a in (!param!) do (
echo %%a
set d[%p%]=%%a
getting only this id%%20num in the first iteration from the for loop.
I even tried "param",then the entire value with quotes is retrieved but after removing the " using !param:"=! the %%a,%%b,%%c are not getting replaced with the actual values read from the file down the line.
---------------------------------------------------------------------------------details requested by Comp.
I have a config.bat file where iam passing the parameters.
config.bat
set N=2
set FilterFile=\productfilter.csv \empfilter.csv
set Filterworksheet=/views/xxxxxx/productFilters.csv /views/xxxxxx/empFilters.csv
set param=product%%20num=%%c^&:product%%20Name=%%a^&:product%%20id=%%b emp%%20num=%%c^&:emp%%20Name=%%a^&:emp%%20id=%%b
Script.bat
#echo off
call config.bat
setlocal enabledelayedexpansion
:check
set /a counter=1
if %counter% LEQ %N% GOTO :array
if %counter% GTR %N% GOTO :checkparam
:array
for %%a in ("%Filterworksheet%") do (
set a[%counter%]=%%a
echo !a[%counter%]!
set /a counter=%counter%+1
goto :check
)
:checkparam
set /a p=1
if %p% LEQ %N% GOTO :arrayparam
if %p% GTR %N% GOTO :LOGIC
:arrayparam
for %%a in (%param%) do (
echo %%a
set d[%p%]=%%a
set /a p=%p%+1
goto :checkparam
)
:LOGIC
SET /a c=1
SET /a counter=1
set /a p=1
:COUNTER
if %c% LEQ %N% GOTO :GET
if %c% GTR %N% GOTO :EXIT
:GET
echo !a[%counter%]!
REM -gets the filter worksheet in csv
"tabcmd.exe" get !a[%counter%]! --filename %FilterFile%
for /f "tokens=1-26 delims=," %%a in (%FilterFile%) do (
ECHO !d[%p%]!
)
SET /A counter=%counter%+1
SET /A c=%c%+1
SET /A p=%p%+1
goto :counter
EndLocal
%FilterFile% -\productfilter.csv has the below data.The data can have N number of rows.
productname productid productnum
xyz 11 23
qqq 12 34
So in the first iteration the echo should give the below output
product%%20num=11^&:product%%20Name=xyz^&:product%%20id=23
product%%20num=12^&:product%%20Name=qqq^&:product%%20id=34
In the second iteration,%FilterFile% -\empfilter.csv has the below data.The data can have N number of rows.
empname empid empnum
xyz 11 23
qqq 12 34
So in the second iteration the echo should give the below output
emp%%20num=11^&:emp%%20Name=xyz^&:emp%%20id=23
emp%%20num=12^&:emp%%20Name=qqq^&:emp%%20id=34
:arrayparam is causing the error & was not expected at this time.I am looking for a dynamic load of array.Param can have N number of values delimited by spaces and this should be loaded in to array.
EDIT
Updating the question more clearly.
I have a param variable which is dynamic ie.it can have N number of values delimited by spaces.As an example the below param has two values.But it can 3 or 4 values delimted by space.each key value pair will be separated by &.This is basically the syntax of tabcmd get.
SET PARAM=productname=%%a&productid=%%b empid=%%a&empname=%%b&empad=%%c ...
My requirement is to parse param not as string and load each of the values that are delimited by space into an array.Please note that array indexing should be dynamic since the number of parameters in param is dynamic.So in the above case there will be two array index,
a[0]=productname=%%a&productid=%%b a[1]=empid=%%a&empname=%%b&empad=%%c
There can be a[3] or a[4] based on the number of parameter values. So the index should be dynamic.
Once the array is ready, I will feeding this inside a for loop which reads a file having the actual values for the variables mentioned in the param(product name,productid in the first iteration and emp details in the second iteration since we have only two values in this case).So there %%a, %%b, %%c should get replaced with the read actual values.
Why I mentioned not as a string is that if we parse param as a string then the %%a, %%b values wont get replaced with actual values from file.
I tired to read param in for loop without adding quotes then an error is throwing & was not expecting at this time
Can someone provide suggestions to load the array dynamically without considering the param as string and the array index should be dynamic.
TIA

get a number from txt add 1 and write it back in bat file

The titles says everything, I have a txt file called totalcred.txt with a number, all I want to do is:
keep the number written on the .txt file in a variable
add +195 to this variable
replace the old number with the newer (the one who got +195)
But nothing on this earth worked until now, I got dissapointed.
Here's my code so for (I tried lot of things too):
FOR /F "tokens=1" %%a IN (totalcred.txt) DO (
set val=%%a
IF [%val%] GEQ [0] (
set /a val += 195
echo %val% > totalcred.txt
)
)
You don't even need a for loop, which as you can imagine is problematic when trying to read from the same file you're writing to:
#Echo Off
Set/P "val="<totalcred.txt
If %val% GEq 30000 GoTo :EOF
Set/A "val+=195"
(Echo(%val%)>totalcred.txt
FOR /F "tokens=1 delims=" %%a IN (totalcred.txt) DO (
set /a val=%%a+0
goto con
)
:con
set /a val2=%val%+100
echo %val2%
(Echo(%val2%)>totalcred.txt

Windows batch event reminder for next day

How do I write a batch script, that would search in Dates.txt file of this format:
EventName1 : dd.mm.yyyy
EventName2 : dd.mm.yyyy
...
EventNameN : dd.mm.yyyy
for events with tomorrow's date, and if found, notify the user about them?
I was able to write a script for today's events:
#echo off
setlocal disableDelayedExpansion
IF NOT EXIST Dates.txt GOTO not_found_dates
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
set ldt=%ldt:~6,2%.%ldt:~4,2%.%ldt:~0,4%
echo Today: %ldt%
for /f "tokens=1,2 delims=:" %%A in (Dates.txt) do (
if "%%B"==" %ldt%" echo You have %%Atoday!
)
GOTO:EOF
:not_found_dates
echo Dates.txt not found!
GOTO:EOF
But I can't figure out how to find tomorrow's date to compare it with the dates in file.
Some help would be appreciated!
Well, I have finally figured it myself!
#echo off
setlocal DisableDelayedExpansion
if not exist Dates.txt goto not_found_dates
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
set d=%ldt:~6,2%
set m=%ldt:~4,2%
set y=%ldt:~0,4%
set ldt=%d%.%m%.%y%
echo ************************
echo * Today: %ldt% *
:loop
set /a d=1%d%-99
if %d% gtr 31 (
set d=1
set /a m=1%m%-99
if %m% gtr 12 (
set m=1
set /a y+=1
)
)
xcopy /d:%m%-%d%-%y% /l . .. >nul 2>&1 || goto loop
set td=0%d%
set td=%td:~-2%
set tm=0%m%
set tm=%tm:~-2%
set ty=%y%
set tomorrow=%td%.%tm%.%ty%
echo * Tomorrow: %tomorrow% *
echo ************************
for /f "tokens=1,2 delims=:" %%A in (Dates.txt) do (
if "%%B"==" %tomorrow%" echo # You have %%Atomorrow!
)
goto :EOF
:not_found_dates
echo Dates.txt not found!
goto :EOF
It works for the Dates.txt file, that uses dates in this format:
EventName1 : 31.05.2016
EventName2 : 30.05.2016
EventName3 : 31.05.2016
EventName4 : 01.06.2016
EventName5 : 31.05.2016
EventName6 : 02.06.2016
EventName7 : 01.06.2016
(Shouldn't forget about single empty spaces before and after colon, and about leading zeros for days and months that are less than 10.)
UPDATE:
At first, set /a d+=1 adds a day.
Then, this line:
xcopy /d:%m%-%d%-%y% /l . .. >nul 2>&1 || goto loop
checks if the date that was formed by set /a d+=1 part, actually exists in the calendar. If the date that was formed doesn't exist, it just "skips" the date, moving to the beginning of the loop to add one more day. This way, the date that doesn't exist can't be set as tomorrow's date.
The if %d% gtr 31 ( part is not doing anything unless it is actually 31st day of month today.
So, despite the if %d% gtr 31 ( part that looks somewhat confusing, this code still works well for months that have less than 31 days in them.
To understand it all better, turn #echo on and trace the changes in the date values.
For example, if we use:
set d=30
set m=04
set y=2016
Output is:
************************
* Today: 30.04.2016 *
* Tomorrow: 01.05.2016 *
************************
Also, for:
set d=28
set m=02
set y=2015
Output:
************************
* Today: 28.02.2015 *
* Tomorrow: 01.03.2015 *
************************
Here is a pure batch file solution to calculate tomorrow's date from current date with remarks explaining the code. The lines with remark command rem can be removed for faster processing the batch file by Windows command processor.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" (
rem Get local date and time in a region independent format.
for /F "skip=1 tokens=1 delims=." %%D in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime') do set "LocalDateTime=%%D" & goto GetDate
) else (
rem This is for fast testing determining the date of tomorrow from any
rem date specified as parameter in format yyyyMMdd on calling this batch
rem file from within a command prompt window. The parameter string is
rem not validated at all as this is just for testing the code below.
set "LocalDateTime=%~1"
)
rem Get day, month and year from the local date/time string (or parameter).
:GetDate
set "Day=%LocalDateTime:~6,2%"
set "Month=%LocalDateTime:~4,2%"
set "Year=%LocalDateTime:~0,4%"
rem Define a variable with today's date in format dd.MM.yyyy
set "Today=%Day%.%Month%.%Year%"
rem Increase the day in month by 1 in any case.
rem It is necessary to remove leading 0 for the days 08 and 09 as
rem those two days would be otherwise interpreted as invalid octal
rem numbers and increment result would be 1 instead of 9 and 10.
rem if "%Day:~0,1%" == "0" set "Day=%Day:~1%"
rem set /A Day+=1
rem Faster is concatenating character 1 with the day string to string
rem representing 101 to 131 and subtract 99 to increment day by one.
set /A Day=1%Day%-99
rem The tomorrow's date is already valid if the day of month is less than 29.
if %Day% LSS 29 goto BuildTomorrow
rem Tomorrow is next month if day is equal (or greater) 32.
if %Day% GEQ 32 goto NextMonth
rem Day 31 in month is not possible in April, June, September and November.
rem In February it can't occur that day in month increased from 30 to 31
rem except on calling this batch file with invalid date string 20160230.
if %Day% EQU 31 (
if %Month% == 04 goto NextMonth
if %Month% == 06 goto NextMonth
if %Month% == 09 goto NextMonth
if %Month% == 11 goto NextMonth
)
rem The day 29 and 30 in month is valid for all months except February.
if NOT %Month% == 02 goto BuildTomorrow
rem Determine if this year is a leap year with 29 days in February.
set /A LeapYearRule1=Year %% 400
set /A LeapYearRule2=Year %% 100
set /A LeapYearRule3=Year %% 4
rem The current year is always a leap year if it can be divided by 400
rem with 0 left over (1600, 2000, 2400, ...). Otherwise if the current
rem year can be divided by 100 with 0 left over, the current year is NOT
rem a leap year (1900, 2100, 2200, 2300, 2500, ...). Otherwise the current
rem year is a leap year if the year can be divided by 4 with 0 left over.
rem Well, for the year range 1901 to 2099 just leap year rule 3 would be
rem enough and just last IF condition would be enough for this year range.
set "LastFebruaryDay=28"
if %LeapYearRule1% == 0 (
set "LastFebruaryDay=29"
) else if NOT %LeapYearRule2% == 0 (
if %LeapYearRule3% == 0 (
set "LastFebruaryDay=29"
)
)
if %Day% LEQ %LastFebruaryDay% goto BuildTomorrow
rem Tomorrow is next month. Therefore set day in month to 1, increase the
rem month by 1 and if now greater than 12, set month to 1 and increase year.
:NextMonth
set "Day=1"
set /A Month=1%Month%-99
if %Month% GTR 12 (
set "Month=1"
set /A Year+=1
)
rem The leading 0 on month and day in month could be removed and so both
rem values are defined again as string with a leading 0 added and next just
rem last two characters are kept to get day and month always with two digits.
:BuildTomorrow
set "Day=0%Day%"
set "Day=%Day:~-2%"
set "Month=0%Month%"
set "Month=%Month:~-2%"
rem Define a variable with tomorrow's date in format dd.MM.yyyy
set "Tomorrow=%Day%.%Month%.%Year%"
echo Today is: %Today%
echo Tomorrow is: %Tomorrow%
endlocal
Please read my answer on Why does %date% produce a different result in batch file executed as scheduled task? It explains in full details the FOR command line using WMIC to get current date in region independent format.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
wmic OS get /?

Windows console %DATE% Math

I would like to set the date in a Windows batch file to 7 days ago from today. I would like to do this in the following format.
set today=%date:~10,4%-%date:~4,2%-%date:~-7,2%
Any ideas how to subract the 7 day time delta here ?
I posted the description below in some site some time ago:
The following Batch files convert from Date to Julian Day Number an viceversa:
DATETOJULIAN.BAT:
#ECHO OFF
REM CONVERT DATE TO JULIAN DAY NUMBER
REM ANTONIO PEREZ AYALA
REM GET MONTH, DAY, YEAR VALUES
FOR /F "TOKENS=1-3 DELIMS=/" %%A IN ("%1") DO SET MM=%%A& SET DD=%%B& SET YY=%%C
REM ELIMINATE LEFT ZEROS
SET /A DD=10%DD% %% 100, MM=10%MM% %% 100
REM CALCULATE JULIAN DAY NUMBER
IF %MM% LSS 3 SET /A MM+=12, YY-=1
SET /A A=YY/100, B=A/4, C=2-A+B, E=36525*(YY+4716)/100, F=306*(MM+1)/10, JDN=C+DD+E+F-1524
JULIANTODATE.BAT:
REM CONVERT JULIAN DAY NUMBER TO MONTH, DAY, YEAR
REM ANTONIO PEREZ AYALA
SET /A W=(%1*100-186721625)/3652425, X=W/4, A=%1+1+W-X, B=A+1524, C=(B*100-12210)/36525, D=36525*C/100, E=(B-D)*10000/306001, F=306001*E/10000, DD=B-D-F, MM=E-1, YY=C-4716
IF %MM% GTR 12 SET /A MM-=12, YY+=1
REM INSERT LEFT ZEROS, IF NEEDED
IF %DD% LSS 10 SET DD=0%DD%
IF %MM% LSS 10 SET MM=0%MM%
REM SHOW THE DATE
ECHO %MM%/%DD%/%YY%
This way, to add/subtract a number of days to a date use the following lines:
CALL DATETOJULIAN %DATE%
SET /A NEWDATE=JDN+DAYS
CALL JULIANTODATE %NEWDATE%
Regards...
Reference: http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
You just need to adjust your date format if it is not MM/DD/YYYY.
AdamEstrada asked about subtracting dates.
I had a tough time subtracting two Julian dates because of the SETLOCAL in the Julian functions. I did it by calling a function.
call:sub_Julians !Julian! %Today_Julian%
:sub_Julians
set /a delta_dates=%~1-%~2
...
goto:eof ::end:age_of_EPSdate
Ok, I needed a batch file to display the current JDAY for an DoD operations center. You can double-click the file and it will display in a CMD window. Then, press any key to exit.
Here's what I came up with:
#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%"
:: Call the day ordinal number subroutine
call :JDdayNumber %DD% %MM% %YYYY% DayOrdinalNumber
:: Display the result
echo.
echo Today is JDay %DayOrdinalNumber%
echo.
pause,
endlocal & goto :EOF
:: set "datestamp=%YYYY%%MM%%DD%" & set "timestamp=%HH%%Min%%Sec%"
:: set "fullstamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%"
:: echo datestamp: "%datestamp%"
:: echo timestamp: "%timestamp%"
:: echo fullstamp: "%fullstamp%"
:: ============================================================
:: Subroutine: Calculate a day's ordinal number within the year
::JDdayNumber day month year return_
setlocal enableextensions enabledelayedexpansion
if %2 LEQ 2 (
set /a f=%1-1+31*^(%2-1^)
) else (
set /a a=%3
set /a b=!a!/4-!a!/100+!a!/400
set /a c=^(!a!-1^)/4-^(!a!-1^)/100+^(!a!-1^)/400
set /a s=!b!-!c!
set /a f=%1+^(153*^(%2-3^)+2^)/5+58+!s!
)
set /a return_=%f%+1
endlocal & set "%4=%return_%" & goto :EOF
I refactored the code of the JDate and GDate subroutines a little bit from http://www.robvanderwoude.com/datetimentmath.php.
Usage example:
Enter ISO date:
Enter number of days to add: 7
2017-01-01 + 7 days = 2017-01-08
Enter ISO date:
Enter number of days to add:
2017-01-08 + 7 days = 2017-01-15
Enter ISO date:
Enter number of days to add:
2017-01-15 + 7 days = 2017-01-22
Enter ISO date:
Enter number of days to add:
2017-01-22 + 7 days = 2017-01-29
Enter ISO date:
Enter number of days to add:
2017-01-29 + 7 days = 2017-02-05
Enter ISO date: 2017-02-12
Enter number of days to add: -7
2017-02-12 + -7 days = 2017-02-05
Code:
"Date math.bat":
#echo off
call :main %*
goto :eof
:main
setlocal
call :initialize "2017-01-01" "1"
endlocal
goto :eof
:initialize
setlocal
set "previousDate=%~1"
set /a "numberOfDays=%~2"
set /p "previousDate=Enter ISO date: "
set /p "numberOfDays=Enter number of days to add: "
set "currentDate="
call :addIsoDateDays "%previousDate%" "%numberOfDays%" currentDate
echo %previousDate% + %numberOfDays% days = %currentDate%
echo.
call :initialize "%currentDate%" "%numberOfDays%"
endlocal
goto :eof
:stripLeadingZero
setlocal
set "number=%~1"
if %number:~0,1% equ 0 (
set "number=%number:~1%"
)
(
endlocal
set "%~2=%number%"
)
goto :eof
:addLeadingZero
setlocal
set "number=%~1"
if %number% lss 10 (
set "number=0%number%"
)
(
endlocal
set "%~2=%number%"
)
goto :eof
:gregorianToJulianDate
setlocal
set "gregorianYear=%~1"
set "gregorianMonth=%~2"
set "gregorianDay=%~3"
call :stripLeadingZero "%gregorianMonth%" gregorianMonth
call :stripLeadingZero "%gregorianDay%" gregorianDay
set /a "julianYear=(%gregorianYear% + 4800)"
set /a "julianMonth=((%gregorianMonth% - 14) / 12)"
set /a "julianDate=((1461 * (%julianYear% + %julianMonth%) / 4) + (367 * (%gregorianMonth% - 2 - (12 * %julianMonth%)) / 12) - ((3 * ((%julianYear% + %julianMonth% + 100) / 100)) / 4) + (%gregorianDay% - 32075))"
(
endlocal
set "%~4=%julianDate%"
)
goto :eof
:isoToJulianDate
setlocal
set "date=%~1"
set "year="
set "month="
set "day="
for /f "tokens=1-3 delims=-" %%a in ("%date%") do (
set "year=%%a"
set "month=%%b"
set "day=%%c"
)
set /a "julianDate=0"
call :gregorianToJulianDate "%year%" "%month%" "%day%" julianDate
(
endlocal
set "%~2=%julianDate%"
)
goto :eof
:julianToGregorianDate
setlocal
set /a "julianDate=%~1"
set /a "p=(%julianDate% + 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 "gregorianYear=((100 * (%q% - 49)) + %s% + %v%)"
set /a "gregorianMonth=(%u% + 2 - (12 * %v%))"
set /a "gregorianDay=(%t% - (2447 * %u% / 80))"
call :addLeadingZero "%gregorianMonth%" gregorianMonth
call :addLeadingZero "%gregorianDay%" gregorianDay
(
endlocal
set "%~2=%gregorianYear%"
set "%~3=%gregorianMonth%"
set "%~4=%gregorianDay%"
)
goto :eof
:julianToIsoDate
setlocal
set /a "julianDate=%~1"
set "year="
set "month="
set "day="
call :julianToGregorianDate "%julianDate%" year month day
set "isoDate=%year%-%month%-%day%"
(
endlocal
set "%~2=%isoDate%"
)
goto :eof
:addIsoDateDays
setlocal
set "previousIsoDate=%~1"
set /a "numberOfDays=%~2"
set /a "previousJulianDate=0"
call :isoToJulianDate "%previousIsoDate%" previousJulianDate
set /a "currentJulianDate=(%previousJulianDate% + %numberOfDays%)"
set "currentIsoDate="
call :julianToIsoDate "%currentJulianDate%" currentIsoDate
(
endlocal
set "%~3=%currentIsoDate%"
)
goto :eof
A simpler option is to call a PowerShell command from within your batch script to manipulate the date. The batch script can set the date as 7 days in the past with a single line.
powershell -command "((Get-date).AddDays(-7)).ToString('yyyy-MM-dd')">captureVar && set /p Today=<captureVar
The line starts out by instructing the cmd line to use PowerShell for the commands contained within the double quotes.
powershell -command "the powershell command(s)"
Next it used the PowerShell cmdlet Get-Date , and uses AddDays to change the date from the current value. A negative number will subtract and a positive number will add. The default format looks like
Friday, December 20, 2019 6:18:29 PM
To change the format you must change the date into a string with format instructions
.ToString('dddd MM/dd/yyyy HH:mm:ss.ffff K')
The output of the PowerShell command is redirected into a file named captureVar. Another option would have been to have PowerShell write it to a file.
powershell -command "((Get-date).AddDays(-7)).ToString('yyyy-MM-dd') | set-content 'captureVar'" && set /p Today=<captureVar
I used && to make it a one liner. But you can set the var anytime after value has been written to the file.
set /p Today=<captureVar
You should write in whatever scripting language you are most comfortable in. But remember that your options when writing a batch script isn't just batch commands. Windows has made it very easy to invoke PowerShell commands at anytime within your batch script. You can often find easy solutions to a given obstacle with PowerShell, insert that command into your script, then carry on as usual to finish your batch script.
A couple of things to remember when invoking PowerShell into your batch script:
Batch sees everything in double quotes as the PowerShell command. If you find a solution written in PowerShell that uses double quotes in the command, you must substitute those with single quotes. To escape characters, follow batch scripting rules. Batch variables can be read in the PowerShell command in the same way as batch (%var%). But values created in PowerShell must be redirected to be used later in your batch script. Any $var created in the PowerShell command is lost once the closing quote closes the PowerShell session.
There's an answer with calling powershell.
Though there are still machines running without powershell installed (at the moment of writing this XP,Vista,Windows7,Windows2003 and Windows2008 still have a descent OS share and are coming without installed powershell)
Other option will be using jscript within a bat script
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());
usage and the output:
E:\scripts>call 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.

Resources