Batch script for time measurement not working properly - time

I'm using a batch script for the time measurement of commands. I have found this script here on StackOverflow. Unfortunately it sometimes is not working properly and unfortunately I don't know much about batch programming. I get the impression that it sometimes works and sometimes not. Perhaps I err on this but it does seem that its not working properly after midnight.
The script:
#echo off
setlocal
rem The format of %TIME% is HH:MM:SS,CS for example 23:59:59,99
set STARTTIME=%TIME%
rem here begins the command you want to measure
dir /s > nul
rem here ends the command you want to measure
set ENDTIME=%TIME%
echo STARTTIME %STARTTIME%
rem convert STARTTIME and ENDTIME to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
echo STARTTIME %STARTTIME%
echo ENDTIME %ENDTIME%
set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
echo ENDTIME %ENDTIME%
rem calculating the duration is easy
set /A DURATION=%ENDTIME%-%STARTTIME%
rem we might have measured the time inbetween days
if %ENDTIME% LSS %STARTTIME% set set /A DURATION=%STARTTIME%-%ENDTIME%
rem outputing
echo DURATION: %DURATION% in centiseconds
endlocal
goto :EOF
I was using it half an hour ago and I got this result:
STARTTIME 1:29:25.17
STARTTIME 1:29:25.17
ENDTIME 1:29:27.82
ENDTIME 1:29:27.82
DURATION: 1 in centiseconds
So something with the lines
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
and
the line
set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
seems to be wrong.
What is it?
Regards,
David

The problem is with "%STARTTIME:~0,2%-100" being " 1", there is an extra space. The program then tries to find the value of (1 1) instead of (101).
The extra 1 in front should only be for systems that output the time as "01:29:25.17" (to give 101 instead of 01 which the system will interpret as octal number), but for systems that output the time as " 1:29:25.17"(Note the space in front of the 1) there is a problem (which will give 1 1).
An easy way is just to remove the 1 in STARTTIME=(1%STARTTIME:~0,2%-100)*360000 and ENDTIME=(1%ENDTIME:~0,2%-100)*360000, though that might cause a problem with other systems.
A more watertight solution would be to add two lines after the rem line:
rem convert STARTTIME and ENDTIME to centiseconds
set STARTTIME=%STARTTIME: =0%
set ENDTIME=%ENDTIME: =0%
(EDIT: Andriy M's much shorter method above)
There are also two set in if %ENDTIME% LSS %STARTTIME% set set /A DURATION=%STARTTIME%-%ENDTIME% which might cause a problem when trying to measure the time between days.

Related

Subtract month in Windows batch

I would like to have this run and show the previous month. When I try to subtract the month it makes the last day of the month field not appear.
#echo off
set FirstDay=01
set Month=%date:~4,2%
set Year=%date:~10,4%
if %Month%==01 set LastDay=31 & goto foundate
if %Month%==02 set LastDay=28 & goto foundate
if %Month%==03 set LastDay=31 & goto foundate
if %Month%==04 set LastDay=30 & goto foundate
if %Month%==05 set LastDay=31 & goto foundate
if %Month%==06 set LastDay=30 & goto foundate
if %Month%==07 set LastDay=31 & goto foundate
if %Month%==08 set LastDay=31 & goto foundate
if %Month%==09 set LastDay=30 & goto foundate
if %Month%==10 set LastDay=31 & goto foundate
if %Month%==11 set LastDay=30 & goto foundate
if %Month%==12 set LastDay=31 & goto foundate
:foundate
echo The year is: %Year%
echo The month is: %Month%
echo First day of this month is: %FirstDay%
echo Last day of this month is: %LastDay%
Dates are complicated to work with and easy to get wrong, and if you can avoid rolling your own, do so.
CMD does not come with a native date library, but the .NET System.DateTime library is available via PowerShell. The following PS script shows how to use .NET to do what you're asking.
Get-LastMonthStats.ps1
$lastmonth = (Get-Date).addMonths(-1)
"The year is $($lastmonth.year)"
"The month is $($lastmonth.Month)"
"First day of this month is 01"
"Last day of this month is $([DateTime]::DaysInMonth($lastmonth.year, $lastmonth.month))"
Nearly all of this script is formatting the output. To run from CMD, launch this with the command
powershell.exe -ex bypass -f Get-LastMonthStats.ps1
Alternatively, you can put the whole script on one (very long) command line, if you don't want to create a separate .ps1 file.
powershell -c "$lastmonth = (Get-Date).addMonths(-1); 'The year is ' + $lastmonth.year; 'The month is ' + $lastmonth.Month; 'First day of this month is 01'; 'Last day of this month is ' + [DateTime]::DaysInMonth($lastmonth.year, $lastmonth.month)"
I made a function library that has these functions. Doing what you want with this library is easy, check below.
The functions are at the end of the code. Just copy to the end of your file (after a goto:eof) and call them using specified arguments.
The given code inside :main should do what you are asking for.
Remarks:
Has inbuilt Leap Year check, so if the year is a Leap Year, Februrary will return 29 days.
When copying functions to your file, please keep Author information
Code:
#echo off
:main
:: Recommended to use GetDateIntl function, to get region-independent results (Check functions at the end of this file)
call :GetDateIntl Year Month Day /A
echo/Using GetDateIntl to get current date: %Year%-%Month%-%day%
echo/
:: Call function to get last day of this month (Check functions at the end of this file)
call :GetLastDayOfMonth %Month% %Year% LastDay
echo This month is: %Month%/%Year%
echo First day of any month is always 1
echo Last day of this month is: %LastDay%
echo/
:: Get previous month number
set /A "PMonth= %Month% - 1"
set "PYear=%Year%"
:: Correct PMonth and PYear if this month is December
if %PMonth%==0 ( set "PMonth=12" & set /A "PYear= %PYear% - 1" )
:: Call function to get last day of previous month (Check function after :main)
call :GetLastDayOfMonth %PMonth% %PYear% PLastDay
echo Previous month is: %PMonth%/%PYear%
echo Last day of previous month is: %PLastDay%
goto:eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetDateIntl yy mm dd [/A]
:: Returns the current date on any machine with regional-independent settings
:: Arguments:
:: yy = variable name for the year output
:: mm = variable name for the month output
:: dd = variable name for the day output
:: /A = OPTIONAL, removes leading 0 on days/months smaller than 10
::
:: By Cyberponk, v1.1 - 11/05/2016
:: v1.0 - 2015
::
SETLOCAL ENABLEEXTENSIONS
if "%date%A" LSS "A" (set toks=1-3) else (set toks=2-4)
for /f "tokens=2-4 delims=(-)" %%a in ('echo:^|date') do (
for /f "tokens=%toks% delims=.-/ " %%i in ('date/t') do (
set '%%a'=%%i
set '%%b'=%%j
set '%%c'=%%k
)
)
if "%'yy'%"=="" set 'yy'=%'aa'%
if %'yy'% LSS 100 set 'yy'=20%'yy'%
endlocal&set %1=%'yy'%&set %4 %2=%'mm'%&set %4 %3=%'dd'%&goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:IsLeapYear %year% IsLeap
:: Checks if a year is a Leap Year (year that has 366 days)
:: Arguments:
:: %year% = year number input. Can be a number or a variable containing a 4 digit number
:: IsLeap = result output containing 1 or 0 (1= is leap year, 0= not yeap lear)
::
:: By Cyberponk, v1.1 - 11/05/2016
::
SETLOCAL ENABLEEXTENSIONS
set /A "IsLeap=(!(%1 %% 4) & !!(%1 %% 100)) | !(%1 %% 400)"
endlocal & set %2=%IsLeap%& goto:EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetLastDayOfMonth %month% %year% LastDay
:: Gets the last day of a given month from a given year
:: Arguments:
:: %month% = month number input. Can be a number or a variable containing a number
:: %year% = year for reference (used to check for leap years)
:: LastDay = result output containing last day of the specified month
::
:: By Cyberponk, v1.0 - 11/05/2016
::
SETLOCAL ENABLEEXTENSIONS
:: Mathematical formula to last day of month
set /A "LastDay= 28 + (%1 + (%1/8)) %% 2 + 2 %% %1 + 2 * (1/%1)
:: Add 1 day if year is a Leap Year and month is February
call :IsLeapYear %2 IsLeap
if %LastDay%==28 set /A LastDay=%LastDay% + %IsLeap%
endlocal & set %3=%LastDay%& goto:EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
here's a piece of code that will get the previous month:
#echo off
for /f "" %%# in ('WMIC Path Win32_LocalTime Get month /format:value') do (
for /f %%Z in ("%%#") do set /a %%Z-1
)
if %month% equ 0 set month=12
echo %month%
Better use wmic to get the date parts because it's independent from the machine's date format unlike the %date% variable.
EDIT (as requested in the comments) :
#echo off
setlocal disableDelayedExpansion
for /f "" %%# in ('"WMIC Path Win32_LocalTime Get month,year /format:value"') do (
for /f %%Z in ("%%#") do set "%%Z"
)
set /a month=month-1
if %month% equ 0 set month=12
rem echo %month% -- %year%
set /A "leap=!(year&3) + (!!(year%%100)-!!(year&15))"
if %leap% equ 0 (set "m2=29") else (set "m2=28")
setlocal enableDelayedExpansion
set m1=31
set m3=31
set m4=30
set m5=31
set m6=30
set m7=31
set m8=31
set m9=30
set m10=31
set m11=30
set m12=31
set premonLastDay=!m%month%!
endlocal & set premonLastDay=%premonLastDay%
if %month% equ 12 (
set /a year=year-1
)
echo %premonLastDay%-%month%-%year%
endlocal
I've modified script of cyberponk for following error
Previous month is: -1/2020
after
if "%'yy'%"=="" set 'yy'=%'aa'%
I've added as fix
if %'mm'% LSS 10 set 'mm'=%'mm':~1,1%

Echo set specific time

I use a code like this to get current time in Windows Bash:
set hour=%TIME:~0,2%
set minute=%TIME:~3,2%
set second=%TIME:~6,2%
But I need a current time +13 seconds. Is there any ways to get this?
Assumming a 24h time hh:mm:ss,cc format,
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "tokens=1-3 delims=:., " %%a in ("%time%") do (
set /a "second=100%%c %% 100 +13", ^
"minute=100%%b %% 100 +second/60", ^
"hour=(100%%a %% 100 +minute/60) %% 24 +100", ^
"minute=minute %% 60 +100", ^
"second=second %% 60 +100"
)
echo %time%
echo %hour:~-2%:%minute:~-2%:%second:~-2%
The time string is tokenized (yes, substring operations are equally valid, but i see this as an easier way), so the hour is retrieved in %%a, minutes in %%b and seconds in %%c and the calcs done
For the three hour elements, the retrieved value from the %time% string are prefixed with 100 and then a mod 100 operation is done, all to avoid the problem with 08 and 09 values being considered as wrong octal values. Once the correct decimal values are retrieved we can operate
second = currentSeconds + 13
minute = currentMinutes + 1 ( if second > 60 )
hour = currentHour + 1 (if minute > 60 ) adjusted to 24h + 100 (for padding)
minute = minute adjusted to 0-59 range + 100 (for padding)
second = second adjusted to 0-59 range + 100 (for padding)
We end with values in the range 100-159 in second, 100-159 in minute, 100-123 in hour. That way we can properly output padded time elements retrieving the last two digits from each of the variables.
Something like the other solutions, but I calculate first the seconds of the day, then adding 13.
And then format the resulting number back to a hh:mm:ss format.
rem ** Calculate the seconds of the day
for /f "tokens=1-3 delims=:., " %%a in ("%time: =0%") do (
set /a "secOfDay=1%%c %% 100 + 60*(1%%b %% 100) + 3600*(1%%a %% 100 )"
)
REM ** Add the desired offset
set /a timePlus13sec=secOfDay+13
REM ** Convert the new time to the HH:mm:ss format
set /a sec=100+timePlus13sec %% 60
set /a temp=timePlus13sec / 60
set /a min=100+temp %% 60
set /a hour=100+(temp / 60) %% 24
echo %hour:~-2%:%min:~-2%:%sec:~-2%
This method uses JScript auxiliary code, so it is always correct:
#echo off
echo d=new Date();d.setTime(d.getTime()+13000);WScript.Echo(d.toString().split(' ')[3]);> test.js
for /F %%a in ('cscript //nologo test.js') do set timeAhead=%%a
echo Time plus 13 seconds: %timeAhead%
I need a current time +13 seconds. Adding 13 and seconds seems to be easiest task, but there are some intricacies:
all numeric values in set /A that start with zeros are treated as
octal but 08 and 09 are not valid octal digits. Cf. next workaround with
%% modulus operator: set /A "val=100%lav%%%100"
more than 59 seconds value affects minutes, more than 59 minutes
value influences hours, more than 23 hours value seems to be impossible
as well...
The script:
#ECHO OFF >NUL
#SETLOCAL
set "myTIME=%TIME%"
call :plus13 "%myTIME%" 6 13 60 second carry
call :plus13 "%myTIME%" 3 %carry% 60 minute carry
call :plus13 "%myTIME%" 0 %carry% 24 hour carry
echo "%myTIME%"
echo "%hour% %minute% %second%"
#ENDLOCAL
#goto :eof
:: plus13 procedure
:: %1 = time value
:: %2 = position in time
:: %3 = value to add
:: %4 = threshold
:: %5 = name of time variable
:: %6 = name of carry variable
:plus13
#SETLOCAL enableextensions enabledelayedexpansion
set "lav=%~1"
set "lav=!lav:~%2,2!"
set /A "val=100%lav%%%100"
set /A "val+=%3"
if %val% GEQ %4 (
set /A "val-=%4"
set /A "car=1"
) else (set /a "car=0")
if %val% LSS 10 set "val=0%val%"
#ENDLOCAL&set %5=%val%&set %6=%car%&goto :eof
Output:
C:\...>time13s
"11:51:49,50"
"11 52 02"

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.

Calculate time difference in Windows batch file

How can I get the difference between two times in a Batch file? Because I want to print it in an HTML file.
I thought this would be possible, but it isn't.
Set "tijd=%time%"
echo %tijd%
echo %time%-%tijd%
Results:
11:07:48,85
11:16:58,99-11:07:48,85
But what I want is:
00:09:10,14
Or 9 minutes and 10 seconds or 550 seconds
#echo off
rem Get start time:
for /F "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
rem Any process here...
rem Get end time:
for /F "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
rem Get elapsed time:
set /A elapsed=end-start
rem Show elapsed time:
set /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100
if %mm% lss 10 set mm=0%mm%
if %ss% lss 10 set ss=0%ss%
if %cc% lss 10 set cc=0%cc%
echo %hh%:%mm%:%ss%,%cc%
EDIT 2017-05-09: Shorter method added
I developed a shorter method to get the same result, so I couldn't resist to post it here. The two for commands used to separate time parts and the three if commands used to insert leading zeros in the result are replaced by two long arithmetic expressions, that could even be combined into a single longer line.
The method consists in directly convert a variable with a time in "HH:MM:SS.CC" format into the formula needed to convert the time to centiseconds, accordingly to the mapping scheme given below:
HH : MM : SS . CC
(((10 HH %%100)*60+1 MM %%100)*60+1 SS %%100)*100+1 CC %%100
That is, insert (((10 at beginning, replace the colons by %%100)*60+1, replace the point by %%100)*100+1 and insert %%100 at end; finally, evaluate the resulting string as an arithmetic expression. In the time variable there are two different substrings that needs to be replaced, so the conversion must be completed in two lines. To get an elapsed time, use (endTime)-(startTime) expression and replace both time strings in the same line.
EDIT 2017/06/14: Locale independent adjustment added
EDIT 2020/06/05: Pass-over-midnight adjustment added
#echo off
setlocal EnableDelayedExpansion
set "startTime=%time: =0%"
set /P "=Any process here..."
set "endTime=%time: =0%"
rem Get elapsed time:
set "end=!endTime:%time:~8,1%=%%100)*100+1!" & set "start=!startTime:%time:~8,1%=%%100)*100+1!"
set /A "elap=((((10!end:%time:~2,1%=%%100)*60+1!%%100)-((((10!start:%time:~2,1%=%%100)*60+1!%%100), elap-=(elap>>31)*24*60*60*100"
rem Convert elapsed time to HH:MM:SS:CC format:
set /A "cc=elap%%100+100,elap/=100,ss=elap%%60+100,elap/=60,mm=elap%%60+100,hh=elap/60+100"
echo Start: %startTime%
echo End: %endTime%
echo Elapsed: %hh:~1%%time:~2,1%%mm:~1%%time:~2,1%%ss:~1%%time:~8,1%%cc:~1%
You may review a detailed explanation of this method at this answer.
As answered here:
How can I use a Windows batch file to measure the performance of console application?
Below batch "program" should do what you want. Please note that it outputs the data in centiseconds instead of milliseconds. The precision of the used commands is only centiseconds.
Here is an example output:
STARTTIME: 13:42:52,25
ENDTIME: 13:42:56,51
STARTTIME: 4937225 centiseconds
ENDTIME: 4937651 centiseconds
DURATION: 426 in centiseconds
00:00:04,26
Here is the batch script:
#echo off
setlocal
rem The format of %TIME% is HH:MM:SS,CS for example 23:59:59,99
set STARTTIME=%TIME%
rem here begins the command you want to measure
dir /s > nul
rem here ends the command you want to measure
set ENDTIME=%TIME%
rem output as time
echo STARTTIME: %STARTTIME%
echo ENDTIME: %ENDTIME%
rem convert STARTTIME and ENDTIME to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
rem calculating the duratyion is easy
set /A DURATION=%ENDTIME%-%STARTTIME%
rem we might have measured the time inbetween days
if %ENDTIME% LSS %STARTTIME% set set /A DURATION=%STARTTIME%-%ENDTIME%
rem now break the centiseconds down to hors, minutes, seconds and the remaining centiseconds
set /A DURATIONH=%DURATION% / 360000
set /A DURATIONM=(%DURATION% - %DURATIONH%*360000) / 6000
set /A DURATIONS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000) / 100
set /A DURATIONHS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000 - %DURATIONS%*100)
rem some formatting
if %DURATIONH% LSS 10 set DURATIONH=0%DURATIONH%
if %DURATIONM% LSS 10 set DURATIONM=0%DURATIONM%
if %DURATIONS% LSS 10 set DURATIONS=0%DURATIONS%
if %DURATIONHS% LSS 10 set DURATIONHS=0%DURATIONHS%
rem outputing
echo STARTTIME: %STARTTIME% centiseconds
echo ENDTIME: %ENDTIME% centiseconds
echo DURATION: %DURATION% in centiseconds
echo %DURATIONH%:%DURATIONM%:%DURATIONS%,%DURATIONHS%
endlocal
goto :EOF
A re-hash of Aacini's code because most likely you are going to set the start time as a variable and want to save that data for output:
#echo off
rem ****************** MAIN CODE SECTION
set STARTTIME=%TIME%
rem Your code goes here (remove the ping line)
ping -n 4 -w 1 127.0.0.1 >NUL
set ENDTIME=%TIME%
rem ****************** END MAIN CODE SECTION
rem Change formatting for the start and end times
for /F "tokens=1-4 delims=:.," %%a in ("%STARTTIME%") do (
set /A "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
for /F "tokens=1-4 delims=:.," %%a in ("%ENDTIME%") do (
IF %ENDTIME% GTR %STARTTIME% set /A "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
IF %ENDTIME% LSS %STARTTIME% set /A "end=((((%%a+24)*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
rem Calculate the elapsed time by subtracting values
set /A elapsed=end-start
rem Format the results for output
set /A hh=elapsed/(60*60*100), rest=elapsed%%(60*60*100), mm=rest/(60*100), rest%%=60*100, ss=rest/100, cc=rest%%100
if %hh% lss 10 set hh=0%hh%
if %mm% lss 10 set mm=0%mm%
if %ss% lss 10 set ss=0%ss%
if %cc% lss 10 set cc=0%cc%
set DURATION=%hh%:%mm%:%ss%,%cc%
echo Start : %STARTTIME%
echo Finish : %ENDTIME%
echo ---------------
echo Duration : %DURATION%
Output:
Start : 11:02:45.92
Finish : 11:02:48.98
---------------
Duration : 00:00:03,06
If you do not mind using powershell within batch script:
#echo off
set start_date=%date% %time%
:: Simulate some type of processing using ping
ping 127.0.0.1
set end_date=%date% %time%
powershell -command "&{$start_date1 = [datetime]::parse('%start_date%'); $end_date1 = [datetime]::parse('%date% %time%'); echo (-join('Duration in seconds: ', ($end_date1 - $start_date1).TotalSeconds)); }"
Aacini's latest code showcases an awesome variable substitution method.
It's a shame it's not Regional format proof - it fails on so many levels.
Here's a short fix that keeps the substitution+math method intact:
#echo off
setlocal EnableDelayedExpansion
set "startTime=%time: =0%" & rem AveYo: fix single digit hour
set /P "=Any process here..."
set "endTime=%time: =0%" & rem AveYo: fix single digit hour
rem Aveyo: Regional format fix with just one aditional line
for /f "tokens=1-3 delims=0123456789" %%i in ("%endTime%") do set "COLON=%%i" & set "DOT=%%k"
rem Get elapsed time:
set "end=!endTime:%DOT%=%%100)*100+1!" & set "start=!startTime:%DOT%=%%100)*100+1!"
set /A "elap=((((10!end:%COLON%=%%100)*60+1!%%100)-((((10!start:%COLON%=%%100)*60+1!%%100)"
rem Aveyo: Fix 24 hours
set /A "elap=!elap:-=8640000-!"
rem Convert elapsed time to HH:MM:SS:CC format:
set /A "cc=elap%%100+100,elap/=100,ss=elap%%60+100,elap/=60,mm=elap%%60+100,hh=elap/60+100"
echo Start: %startTime%
echo End: %endTime%
echo Elapsed: %hh:~1%%COLON%%mm:~1%%COLON%%ss:~1%%DOT%%cc:~1% & rem AveYo: display as regional
pause
*
"Lean and Mean" TIMER with Regional format, 24h and mixed input support
Adapting Aacini's substitution method body, no IF's, just one FOR (my regional fix)
1: File timer.bat placed somewhere in %PATH% or the current dir
#echo off & rem :AveYo: compact timer function with Regional format, 24-hours and mixed input support
if not defined timer_set (if not "%~1"=="" (call set "timer_set=%~1") else set "timer_set=%TIME: =0%") & goto :eof
(if not "%~1"=="" (call set "timer_end=%~1") else set "timer_end=%TIME: =0%") & setlocal EnableDelayedExpansion
for /f "tokens=1-6 delims=0123456789" %%i in ("%timer_end%%timer_set%") do (set CE=%%i&set DE=%%k&set CS=%%l&set DS=%%n)
set "TE=!timer_end:%DE%=%%100)*100+1!" & set "TS=!timer_set:%DS%=%%100)*100+1!"
set/A "T=((((10!TE:%CE%=%%100)*60+1!%%100)-((((10!TS:%CS%=%%100)*60+1!%%100)" & set/A "T=!T:-=8640000-!"
set/A "cc=T%%100+100,T/=100,ss=T%%60+100,T/=60,mm=T%%60+100,hh=T/60+100"
set "value=!hh:~1!%CE%!mm:~1!%CE%!ss:~1!%DE%!cc:~1!" & if "%~2"=="" echo/!value!
endlocal & set "timer_end=%value%" & set "timer_set=" & goto :eof
Usage:
timer & echo start_cmds & timeout /t 3 & echo end_cmds & timer
timer & timer "23:23:23,00"
timer "23:23:23,00" & timer
timer "13.23.23,00" & timer "03:03:03.00"
timer & timer "0:00:00.00" no & cmd /v:on /c echo until midnight=!timer_end!
Input can now be mixed, for those unlikely, but possible time format changes during execution
2: Function :timer bundled with the batch script (sample usage below):
#echo off
set "TIMER=call :timer" & rem short macro
echo.
echo EXAMPLE:
call :timer
timeout /t 3 >nul & rem Any process here..
call :timer
echo.
echo SHORT MACRO:
%TIMER% & timeout /t 1 & %TIMER%
echo.
echo TEST INPUT:
set "start=22:04:04.58"
set "end=04.22.44,22"
echo %start% ~ start & echo %end% ~ end
call :timer "%start%"
call :timer "%end%"
echo.
%TIMER% & %TIMER% "00:00:00.00" no
echo UNTIL MIDNIGHT: %timer_end%
echo.
pause
exit /b
:: to test it, copy-paste both above and below code sections
rem :AveYo: compact timer function with Regional format, 24-hours and mixed input support
:timer Usage " call :timer [input - optional] [no - optional]" :i Result printed on second call, saved to timer_end
if not defined timer_set (if not "%~1"=="" (call set "timer_set=%~1") else set "timer_set=%TIME: =0%") & goto :eof
(if not "%~1"=="" (call set "timer_end=%~1") else set "timer_end=%TIME: =0%") & setlocal EnableDelayedExpansion
for /f "tokens=1-6 delims=0123456789" %%i in ("%timer_end%%timer_set%") do (set CE=%%i&set DE=%%k&set CS=%%l&set DS=%%n)
set "TE=!timer_end:%DE%=%%100)*100+1!" & set "TS=!timer_set:%DS%=%%100)*100+1!"
set/A "T=((((10!TE:%CE%=%%100)*60+1!%%100)-((((10!TS:%CS%=%%100)*60+1!%%100)" & set/A "T=!T:-=8640000-!"
set/A "cc=T%%100+100,T/=100,ss=T%%60+100,T/=60,mm=T%%60+100,hh=T/60+100"
set "value=!hh:~1!%CE%!mm:~1!%CE%!ss:~1!%DE%!cc:~1!" & if "%~2"=="" echo/!value!
endlocal & set "timer_end=%value%" & set "timer_set=" & goto :eof
Based on previous answers, here are reusable "procedures" and a usage example for calculating the elapsed time:
#echo off
setlocal
set starttime=%TIME%
echo Start Time: %starttime%
REM ---------------------------------------------
REM --- PUT THE CODE YOU WANT TO MEASURE HERE ---
REM ---------------------------------------------
set endtime=%TIME%
echo End Time: %endtime%
call :elapsed_time %starttime% %endtime% duration
echo Duration: %duration%
endlocal
echo on & goto :eof
REM --- HELPER PROCEDURES ---
:time_to_centiseconds
:: %~1 - time
:: %~2 - centiseconds output variable
setlocal
set _time=%~1
for /F "tokens=1-4 delims=:.," %%a in ("%_time%") do (
set /A "_result=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
)
endlocal & set %~2=%_result%
goto :eof
:centiseconds_to_time
:: %~1 - centiseconds
:: %~2 - time output variable
setlocal
set _centiseconds=%~1
rem now break the centiseconds down to hors, minutes, seconds and the remaining centiseconds
set /A _h=%_centiseconds% / 360000
set /A _m=(%_centiseconds% - %_h%*360000) / 6000
set /A _s=(%_centiseconds% - %_h%*360000 - %_m%*6000) / 100
set /A _hs=(%_centiseconds% - %_h%*360000 - %_m%*6000 - %_s%*100)
rem some formatting
if %_h% LSS 10 set _h=0%_h%
if %_m% LSS 10 set _m=0%_m%
if %_s% LSS 10 set _s=0%_s%
if %_hs% LSS 10 set _hs=0%_hs%
set _result=%_h%:%_m%:%_s%.%_hs%
endlocal & set %~2=%_result%
goto :eof
:elapsed_time
:: %~1 - time1 - start time
:: %~2 - time2 - end time
:: %~3 - elapsed time output
setlocal
set _time1=%~1
set _time2=%~2
call :time_to_centiseconds %_time1% _centi1
call :time_to_centiseconds %_time2% _centi2
set /A _duration=%_centi2%-%_centi1%
call :centiseconds_to_time %_duration% _result
endlocal & set %~3=%_result%
goto :eof
Fixed Gynnad's leading 0 Issue. I fixed it with the two Lines
SET STARTTIME=%STARTTIME: =0%
SET ENDTIME=%ENDTIME: =0%
Full Script ( CalculateTime.cmd ):
#ECHO OFF
:: F U N C T I O N S
:__START_TIME_MEASURE
SET STARTTIME=%TIME%
SET STARTTIME=%STARTTIME: =0%
EXIT /B 0
:__STOP_TIME_MEASURE
SET ENDTIME=%TIME%
SET ENDTIME=%ENDTIME: =0%
SET /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
SET /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
SET /A DURATION=%ENDTIME%-%STARTTIME%
IF %DURATION% == 0 SET TIMEDIFF=00:00:00,00 && EXIT /B 0
IF %ENDTIME% LSS %STARTTIME% SET /A DURATION=%STARTTIME%-%ENDTIME%
SET /A DURATIONH=%DURATION% / 360000
SET /A DURATIONM=(%DURATION% - %DURATIONH%*360000) / 6000
SET /A DURATIONS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000) / 100
SET /A DURATIONHS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000 - %DURATIONS%*100)
IF %DURATIONH% LSS 10 SET DURATIONH=0%DURATIONH%
IF %DURATIONM% LSS 10 SET DURATIONM=0%DURATIONM%
IF %DURATIONS% LSS 10 SET DURATIONS=0%DURATIONS%
IF %DURATIONHS% LSS 10 SET DURATIONHS=0%DURATIONHS%
SET TIMEDIFF=%DURATIONH%:%DURATIONM%:%DURATIONS%,%DURATIONHS%
EXIT /B 0
:: U S A G E
:: Start Measuring
CALL :__START_TIME_MEASURE
:: Print Message on Screen without Linefeed
ECHO|SET /P=Execute Job...
:: Some Time pending Jobs here
:: '> NUL 2>&1' Dont show any Messages or Errors on Screen
MyJob.exe > NUL 2>&1
:: Stop Measuring
CALL :__STOP_TIME_MEASURE
:: Finish the Message 'Execute Job...' and print measured Time
ECHO [Done] (%TIMEDIFF%)
:: Possible Result
:: Execute Job... [Done] (00:02:12,31)
:: Between 'Execute Job... ' and '[Done] (00:02:12,31)' the Job will be executed
Here is my attempt to measure time difference in batch.
It respects the regional format of %TIME% without taking any assumptions on type of characters for time and decimal separators.
The code is commented but I will also describe it here.
It is flexible so it can also be used to normalize non-standard time values as well
The main function :timediff
:: timediff
:: Input and output format is the same format as %TIME%
:: If EndTime is less than StartTime then:
:: EndTime will be treated as a time in the next day
:: in that case, function measures time difference between a maximum distance of 24 hours minus 1 centisecond
:: time elements can have values greater than their standard maximum value ex: 12:247:853.5214
:: provided than the total represented time does not exceed 24*360000 centiseconds
:: otherwise the result will not be meaningful.
:: If EndTime is greater than or equals to StartTime then:
:: No formal limitation applies to the value of elements,
:: except that total represented time can not exceed 2147483647 centiseconds.
:timediff <outDiff> <inStartTime> <inEndTime>
(
setlocal EnableDelayedExpansion
set "Input=!%~2! !%~3!"
for /F "tokens=1,3 delims=0123456789 " %%A in ("!Input!") do set "time.delims=%%A%%B "
)
for /F "tokens=1-8 delims=%time.delims%" %%a in ("%Input%") do (
for %%A in ("#h1=%%a" "#m1=%%b" "#s1=%%c" "#c1=%%d" "#h2=%%e" "#m2=%%f" "#s2=%%g" "#c2=%%h") do (
for /F "tokens=1,2 delims==" %%A in ("%%~A") do (
for /F "tokens=* delims=0" %%B in ("%%B") do set "%%A=%%B"
)
)
set /a "#d=(#h2-#h1)*360000+(#m2-#m1)*6000+(#s2-#s1)*100+(#c2-#c1), #sign=(#d>>31)&1, #d+=(#sign*24*360000), #h=(#d/360000), #d%%=360000, #m=#d/6000, #d%%=6000, #s=#d/100, #c=#d%%100"
)
(
if %#h% LEQ 9 set "#h=0%#h%"
if %#m% LEQ 9 set "#m=0%#m%"
if %#s% LEQ 9 set "#s=0%#s%"
if %#c% LEQ 9 set "#c=0%#c%"
)
(
endlocal
set "%~1=%#h%%time.delims:~0,1%%#m%%time.delims:~0,1%%#s%%time.delims:~1,1%%#c%"
exit /b
)
Example:
#echo off
setlocal EnableExtensions
set "TIME="
set "Start=%TIME%"
REM Do some stuff here...
set "End=%TIME%"
call :timediff Elapsed Start End
echo Elapsed Time: %Elapsed%
pause
exit /b
:: put the :timediff function here
Explanation of the :timediff function:
function prototype :timediff <outDiff> <inStartTime> <inEndTime>
Input and output format is the same format as %TIME%
It takes 3 parameters from left to right:
Param1: Name of the environment variable to save the result to.
Param2: Name of the environment variable to be passed to the function containing StartTime string
Param3: Name of the environment variable to be passed to the function containing EndTime string
If EndTime is less than StartTime then:EndTime will be treated as a time in the next day
in that case, the function measures time difference between a maximum distance of 24 hours minus 1 centisecond
time elements can have values greater than their standard maximum value ex: 12:247:853.5214
provided than the total represented time does not exceed 24*360000 centiseconds or (24:00:00.00) otherwise the result will not be meaningful.
If EndTime is greater than or equals to StartTime then:
No formal limitation applies to the value of elements,
except that total represented time can not exceed 2147483647 centiseconds.
More examples with literal and non-standard time values
Literal example with EndTime less than StartTime:
#echo off
setlocal EnableExtensions
set "start=23:57:33,12"
set "end=00:02:19,41"
call :timediff dif start end
echo Start Time: %start%
echo End Time: %end%
echo,
echo Difference: %dif%
echo,
pause
exit /b
:: put the :timediff function here
Output:
Start Time: 23:57:33,12
End Time: 00:02:19,41
Difference: 00:04:46,29
Normalize non-standard time:
#echo off
setlocal EnableExtensions
set "start=00:00:00.00"
set "end=27:2457:433.85935"
call :timediff normalized start end
echo,
echo %end% is equivalent to %normalized%
echo,
pause
exit /b
:: put the :timediff function here
Output:
27:2457:433.85935 is equivalent to 68:18:32.35
Last bonus example:
#echo off
setlocal EnableExtensions
set "start=00:00:00.00"
set "end=00:00:00.2147483647"
call :timediff normalized start end
echo,
echo 2147483647 centiseconds equals to %normalized%
echo,
pause
exit /b
:: put the :timediff function here
Output:
2147483647 centiseconds equals to 5965:13:56.47
Using a single function with the possibility of custom unit of measure or formatted.
Each time the function is called without parameters we restarted the initial time.
#ECHO OFF
ECHO.
ECHO DEMO timer function
ECHO --------------------
SET DELAY=4
:: First we call the function without any parameters to set the starting time
CALL:timer
:: We put some code we want to measure
ECHO.
ECHO Making some delay, please wait...
ECHO.
ping -n %DELAY% -w 1 127.0.0.1 >NUL
:: Now we call the function again with the desired parameters
CALL:timer elapsed_time
ECHO by Default : %elapsed_time%
CALL:timer elapsed_time "s"
ECHO in Seconds : %elapsed_time%
CALL:timer elapsed_time "anything"
ECHO Formatted : %elapsed_time% (HH:MM:SS.CS)
ECHO.
PAUSE
:: Elapsed Time Function
:: -----------------------------------------------------------------------
:: The returned value is in centiseconds, unless you enter the parameters
:: to be in another unit of measure or with formatted
::
:: Parameters:
:: <return> the returned value
:: [formatted] s (for seconds), m (for minutes), h (for hours)
:: anything else for formatted output
:: -----------------------------------------------------------------------
:timer <return> [formatted]
SetLocal EnableExtensions EnableDelayedExpansion
SET _t=%time%
SET _t=%_t::0=: %
SET _t=%_t:,0=, %
SET _t=%_t:.0=. %
SET _t=%_t:~0,2% * 360000 + %_t:~3,2% * 6000 + %_t:~6,2% * 100 + %_t:~9,2%
SET /A _t=%_t%
:: If we call the function without parameters is defined initial time
SET _r=%~1
IF NOT DEFINED _r (
EndLocal & SET TIMER_START_TIME=%_t% & GOTO :EOF
)
SET /A _t=%_t% - %TIMER_START_TIME%
:: In the case of wanting a formatted output
SET _f=%~2
IF DEFINED _f (
IF "%_f%" == "s" (
SET /A "_t=%_t% / 100"
) ELSE (
IF "%_f%" == "m" (
SET /A "_t=%_t% / 6000"
) ELSE (
IF "%_f%" == "h" (
SET /A "_t=%_t% / 360000"
) ELSE (
SET /A "_h=%_t% / 360000"
SET /A "_m=(%_t% - !_h! * 360000) / 6000"
SET /A "_s=(%_t% - !_h! * 360000 - !_m! * 6000) / 100"
SET /A "_cs=(%_t% - !_h! * 360000 - !_m! * 6000 - !_s! * 100)"
IF !_h! LSS 10 SET "_h=0!_h!"
IF !_m! LSS 10 SET "_m=0!_m!"
IF !_s! LSS 10 SET "_s=0!_s!"
IF !_cs! LSS 10 SET "_cs=0!_cs!"
SET "_t=!_h!:!_m!:!_s!.!_cs!"
SET "_t=!_t:00:=!"
)
)
)
)
EndLocal & SET %~1=%_t%
goto :EOF
A test with a delay of 94 sec
DEMO timer function
--------------------
Making some delay, please wait...
by Default : 9404
in Seconds : 94
Formatted : 01:34.05 (HH:MM:SS.CS)
Presione una tecla para continuar . . .
CMD doesn't have time arithmetic. The following code, however gives a workaround:
set vid_time=11:07:48
set srt_time=11:16:58
REM Get time difference
set length=%vid_time%
for /f "tokens=1-3 delims=:" %i in ("%length%") do (
set /a h=%i*3600
set /a m=%j*60
set /a s=%k
)
set /a t1=!h!+!m!+!s!
set length=%srt_time%
for /f "tokens=1-3 delims=:" %i in ("%length%") do (
set /a h=%i*3600
set /a m=%j*60
set /a s=%k
)
set /a t2=!h!+!m!+!s!
cls
set /a diff=!t2!-!t1!
Above code gives difference in seconds. To display in hh:mm:ss format, code below:
set ss=!diff!
set /a hh=!ss!/3600 >nul
set /a mm="(!ss!-3600*!hh!)/60" >nul
set /a ss="(!ss!-3600*!hh!)-!mm!*60" >nul
set "hh=0!hh!" & set "mm=0!mm!" & set "ss=0!ss!"
echo|set /p=!hh:~-2!:!mm:~-2!:!ss:~-2!
set START=23:05:15
set END=07:02:05
set options="tokens=1-4 delims=:."
for /f %options% %%a in ("%start%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100
for /f %options% %%a in ("%end%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100
set /a hours=%end_h%-%start_h%
set /a mins=%end_m%-%start_m%
set /a secs=%end_s%-%start_s%
set /a ms=%end_ms%-%start_ms%
if 1%ms% lss 100 set ms=0%ms%
if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms%
if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs%
if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins%
if %hours% lss 0 set /a hours = 24%hours%
set hours=0%hours%
set hours=%hours:~-2%
set mins=0%mins%
set mins=%mins:~-2%
set secs=0%secs%
set secs=%secs:~-2%
set /a totalsecs = %hours%*3600 + %mins%*60 + %secs%
echo Command took %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total)
echo %date% %start% - %end% ( %hours%:%mins%:%secs% )
pause

How can I use a Windows batch file to measure the performance of console application?

How can I write a simple batch file to measure the performance of a console-based application? The console application accepts two command line arguments.
I would like to get:
StartTime = System Dos time
myconsoleapp arg1, arg2
StopTime = System Dos Time
timeDelta = stoptime - starttime
I would write the timeDelta to a file or display on the console.
A pure batch solution could be.
#echo off
set "startTime=%time%"
for /L %%n in (1,1, 1000) do <nul set /p "="
set "stopTime=%time%"
call :timeDiff diff startTime stopTime
echo %diff% milli seconds
goto :eof
:timeDiff
setlocal
call :timeToMS time1 "%~2"
call :timeToMS time2 "%~3"
set /a diff=time2-time1
(
ENDLOCAL
set "%~1=%diff%"
goto :eof
)
:timeToMS
::### WARNING, enclose the time in " ", because it can contain comma seperators
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2,3,4 delims=:,.^ " %%a IN ("!%~2!") DO (
set /a "ms=(((30%%a%%100)*60+7%%b)*60+3%%c-42300)*1000+(1%%d0 %% 1000)"
)
(
ENDLOCAL
set %~1=%ms%
goto :eof
)
Below batch "program" should do what you want. Please note that it outputs the data in centiseconds instead of milliseconds. The precision of the used commands is only centiseconds.
Here is an example output:
STARTTIME: 13:42:52,25
ENDTIME: 13:42:56,51
STARTTIME: 4937225 centiseconds
ENDTIME: 4937651 centiseconds
DURATION: 426 in centiseconds
00:00:04,26
Here is the batch script:
#echo off
setlocal
rem The format of %TIME% is HH:MM:SS,CS for example 23:59:59,99
set STARTTIME=%TIME%
rem here begins the command you want to measure
dir /s > nul
rem here ends the command you want to measure
set ENDTIME=%TIME%
rem output as time
echo STARTTIME: %STARTTIME%
echo ENDTIME: %ENDTIME%
rem convert STARTTIME and ENDTIME to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
rem calculating the duratyion is easy
set /A DURATION=%ENDTIME%-%STARTTIME%
rem we might have measured the time inbetween days
if %ENDTIME% LSS %STARTTIME% set set /A DURATION=%STARTTIME%-%ENDTIME%
rem now break the centiseconds down to hors, minutes, seconds and the remaining centiseconds
set /A DURATIONH=%DURATION% / 360000
set /A DURATIONM=(%DURATION% - %DURATIONH%*360000) / 6000
set /A DURATIONS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000) / 100
set /A DURATIONHS=(%DURATION% - %DURATIONH%*360000 - %DURATIONM%*6000 - %DURATIONS%*100)
rem some formatting
if %DURATIONH% LSS 10 set DURATIONH=0%DURATIONH%
if %DURATIONM% LSS 10 set DURATIONM=0%DURATIONM%
if %DURATIONS% LSS 10 set DURATIONS=0%DURATIONS%
if %DURATIONHS% LSS 10 set DURATIONHS=0%DURATIONHS%
rem outputing
echo STARTTIME: %STARTTIME% centiseconds
echo ENDTIME: %ENDTIME% centiseconds
echo DURATION: %DURATION% in centiseconds
echo %DURATIONH%:%DURATIONM%:%DURATIONS%,%DURATIONHS%
endlocal
goto :EOF

Resources