How long does a batch file take to execute? - time

How can I write a script to calculate the time the script took to complete?
I thought this would be the case, but obviously not..
#echo off
set starttime=%time%
set endtime=%time%
REM do stuff here
set /a runtime=%endtime%-%starttime%
echo Script took %runtime% to complete

Two things leap out about the original batch file. but neither is going to help in the long run.
Whatever your benchmark method, be sure to capture the start time before the operation, and the end time after the operation. Your sample doesn't do that.
%time% evaluates to something like "12:34:56.78", and the SET /A command can't subtract those. You need a command that produces a simple scalar time stamp.
I was going to say it can't be done, but the batch language is a lot more powerful than it is given credit for, so here is a simple implementation of TIMER.BAT. For the record, Pax beat me to an answer showing the string splitting while I was fiddling around, and Johannes Rössel suggested moving the arithmetic outside of the measured region:
#echo off
setlocal
rem Remeber start time. Note that we don't look at the date, so this
rem calculation won't work right if the program run spans local midnight.
set t0=%time: =0%
rem do something here.... but probably with more care about quoting.
rem specifically, odd things will happen if any arguments contain
rem precent signs or carets and there may be no way to prevent it.
%*
rem Capture the end time before doing anything else
set t=%time: =0%
rem make t0 into a scaler in 100ths of a second, being careful not
rem to let SET/A misinterpret 08 and 09 as octal
set /a h=1%t0:~0,2%-100
set /a m=1%t0:~3,2%-100
set /a s=1%t0:~6,2%-100
set /a c=1%t0:~9,2%-100
set /a starttime = %h% * 360000 + %m% * 6000 + 100 * %s% + %c%
rem make t into a scaler in 100ths of a second
set /a h=1%t:~0,2%-100
set /a m=1%t:~3,2%-100
set /a s=1%t:~6,2%-100
set /a c=1%t:~9,2%-100
set /a endtime = %h% * 360000 + %m% * 6000 + 100 * %s% + %c%
rem runtime in 100ths is now just end - start
set /a runtime = %endtime% - %starttime%
set runtime = %s%.%c%
echo Started at %t0%
echo Ran for %runtime%0 ms
You could simplify the arithmetic and be a little more honest about the overall accuracy of this by not bothering with the 100ths of a second part. Here it is in action, assuming you have a sleep command or some other time waster:
C:> TIMER SLEEP 3
Script took 3000 ms to complete
C:>
Edit: I revised the code and its description as suggested in a comment.
I think that when the NT team replaced COMMAND.COM with CMD.EXE, they thought they wouldn't get away with making it very different. But in effect, it is almost an entirely new language. Many of the old favorite commands have new features if the extensions are enabled.
One of those is SETLOCAL which prevents variables from modifying the caller's environment. Another is SET /A which gives you a remarkable amount of arithmetic. The principle trick I've used here is the new substring extraction syntax where %t:~3,2% means the two characters starting at offset 3 in the value of the variable named t.
For a real shocker, take a look at the full description of set (try SET /? at a prompt) and if that doesn't scare you, look at FOR /? and notice that it can parse text out of files...
Edit 2: Fixed mis-handling of time fields containing 08 or 09 reported by Frankie in comments. Tweaked a couple of things, and added some comments.
Note that there is a glaring oversight here that I'm probably not going to fix. It won't work if the command starts on a different day than it ends. That is, it will do some math related to the time of day and report a difference, but the difference won't mean much.
Fixing it to at least warn about this case is easy. Fixing it to do the right thing is harder.
Edit 3: Fixed error where the %h% is not set properly for single digit hours. This is due to %time% returning " 9:01:23.45". Notice the space. Using %time: =0% replaces the space with a leading zero and %h% will be set correctly. This error only occurred when a script ran from one single digit hour to the next.

This is kind of tangential, but it may help you out.
Microsoft has a timeit.exe program that works more or less like an enhanced version of the unix 'time' command. It comes in the Windows Server 2003 Resource Kit, and it has pretty much replaced all the times I've wanted to do something like what you're suggesting.
It may be worth a look.

Excellent little routine. However, if the calculation spans across two days, the calculation is incorrect.
The result needs subtracting from 24 hours (8640000 centiseconds).
Also remove one of the duplicate 'set' commands in the relevant line.
Note that regional settings affect the format of the TIME function, the decimal being a fullstop in UK rather than a comma.
The lines
rem we might have measured the time inbetween days
if %ENDTIME% LSS %STARTTIME% set set /A DURATION=%STARTTIME%-%ENDTIME%
need changing to
rem we might have measured the time across days
if %ENDTIME% LSS %STARTTIME% set /A DURATION=8640000 - (%STARTTIME% - %ENDTIME%)

My own personal preference is to install Cygwin and use the time command but, if you actually have to do it as a batch file, you can't just subtract the strings, you have to treat them as parts.
The following script will time a 10-second ping command with the ability to cross a single day boundary without getting tied up in negative numbers. A slight enhancement would allow it to cross many day boundaries.
#echo off
setlocal enableextensions enabledelayedexpansion
set starttime=%time%
ping -n 11 127.0.0.1 >nul: 2>nul:
set endtime=%time%
set /a hrs=%endtime:~0,2%
set /a hrs=%hrs%-%starttime:~0,2%
set /a mins=%endtime:~3,2%
set /a mins=%mins%-%starttime:~3,2%
set /a secs=%endtime:~6,2%
set /a secs=%secs%-%starttime:~6,2%
if %secs% lss 0 (
set /a secs=!secs!+60
set /a mins=!mins!-1
)
if %mins% lss 0 (
set /a mins=!mins!+60
set /a hrs=!hrs!-1
)
if %hrs% lss 0 (
set /a hrs=!hrs!+24
)
set /a tot=%secs%+%mins%*60+%hrs%*3600
echo End = %endtime%
echo Start = %starttime%
echo Hours = %hrs%
echo Minutes = %mins%
echo Seconds = %secs%
echo Total = %tot%
endlocal

Check out this script that will retrieve time through WMI so it's Regional Setting independent.
#echo off
::::::::::::::::::::::::::::::::::::::::::
::  TimeDiff v1.00 by LEVENTE ROG       ::
::       www.thesysadminhimself.com     ::
::::::::::::::::::::::::::::::::::::::::::
 
::[ EULA ]:::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::  Feel free to use this script. The code can be redistributed  ::
::  and edited, but please keep the credits.                     ::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 
::[ CHANGELOG ]::::::::::::::
::  v1.00 - First Version  ::
:::::::::::::::::::::::::::::
 
 
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."') DO (
 set Milisecond=%time:~9,2%
 set Day=%%A
 set Hour=%%B
 set Minute=%%C
 set Second=%%D
)
set /a Start=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100+%Milisecond%
 
::
::
:: PUT COMMANDS HERE
ping www.thesysadminhimself.com
::
::
 
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Second /Format:table ^| findstr /r "."') DO (
 set Day=%%A
 set Hour=%%B
 set Minute=%%C
 set Second=%%D
)
set Milisecond=%time:~9,2%
set /a End=%Day%*8640000+%Hour%*360000+%Minute%*6000+%Second%*100+%Milisecond%
set /a Diff=%End%-%Start%
set /a DiffMS=%Diff%%%100
set /a Diff=(%Diff%-%DiffMS%)/100
set /a DiffSec=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffMin=%Diff%%%60
set /a Diff=(%Diff%-%Diff%%%60)/60
set /a DiffHrs=%Diff%
 
:: format with leading zeroes
if %DiffMS% LSS 10 set DiffMS=0%DiffMS!%
if %DiffSec% LSS 10 set DiffMS=0%DiffSec%
if %DiffMin% LSS 10 set DiffMS=0%DiffMin%
if %DiffHrs% LSS 10 set DiffMS=0%DiffHrs%
 
echo %DiffHrs%:%DiffMin%:%DiffSec%.%DiffMS%

You can't do time arithmetic directly in batch scripting, so you'll either need an external program to calculate the time difference, or extract each part of the time and do arithmetic that way.
Take a look at the bottom of this forum thread for an example of how to do the latter. Excerpted here:
#echo off
cls
REM ================================================== ======
REM = Setting Date Time Format =
REM ================================================== ======
set DT=%DATE% %TIME%
set year=%DT:~10,4%
set mth=%DT:~4,2%
set date=%DT:~7,2%
set hour=%DT:~15,2%
set min=%DT:~18,2%
set sec=%DT:~21,2%
set newDT=%year%_%mth%_%date% %hour%%min%%sec%
set hour=14
set min=10
REM ===============================
REM = Getting End Time =
REM ===============================
set EndTime=%TIME%
set EndHour=%EndTime:~0,2%
set EndMin=%EndTime:~3,2%
REM ===============================
REM = Finding Difference =
REM ===============================
set /a Hour_Diff=EndHour - hour >nul
set /a Min_Diff=EndMin - min >nul
REM ===============================
REM = Hour Hand Change? =
REM ===============================
IF [%Hour_Diff]==[0] (
Set Duration=%Min_Diff%
) ELSE (
Set /a Duration=60-%Min_Diff% >nul
)
echo Start Time = %hour% : %min%
echo End Time = %EndHour% : %EndMin%
echo.
echo Min Diff = %Min_Diff%
echo.
echo time difference (mins) = %Duration%
I also assume it's a typo, but you do want to be sure to set endtime after processing.

Related

How perform arithmetic (add,subtract) between two Date&Time timestamps?

I am trying to create an arbitrary time using batch files. I am trying to subtract set values (such as 1 day, 1 month, and 2000 years) from my code to display the system time subtracted by the set values stated previously. For the hours and minutes, I am subtracting 10 hours and 10 minutes (shown in code as different values). I am also aware that date and time are variables related to my system. ~ Please ignore
Important -
My problem now is with this part:
if %minb% EQU 60 set /a minb=%minb%-60 & set /a hourb=%hourb%+1
if %hourb% EQU 24 set /a hourb=%hourb%-24 & set /a dayb=%dayb%+1
if %dayb% EQU 30 set /a dayb=%dayb%-30 & set /a monthb=%monthb%+1
if %monthb% EQU 12 set /a monthb=%monthb%-12 & set /a yearb=%yearb%+1
I can't seem to be able to make the minutes reset to 0 and have the hours add 1 when the minute value hits 60, and same with the hour-day, day-month, month-year relationships, other than that, the problems with my code are mostly fixed. When I run the code and wait for the minutes (or add to the time difference) to reach 60, they just pass 60 and don't reset nor add to the hoursb value.
.
My date and time formats are:
Short date: M/d/yyyy
Long date: dddd, MMMM d, yyyy
Short time: h:mm
Long time: h:mm:ss
I am using Windows 10.
Please note that the values in the set /a do not match my description, but of course they can be changed around. They are set to the shown numbers for test purposes only.
EDIT:
Code:
#echo off
:start
set day=%date:~-7,2%
set month=%date:~-10,2%
set year=%date:~-4,4%
set hour=%time:~0,2%
set min=%time:~3,2%
set /a "hourb=%hour%-10"
set /a "minb=%min%+30"
set /a "dayb=%day%-1"
set /a "monthb=%month%-1"
set /a "yearb=%year%-2000"
if %minb% lss 10 set minb=0%minb%
if %hourb% lss 10 set hourb=0%hourb%
if %dayb% lss 10 set dayb=0%dayb%
if %monthb% lss 10 set monthb=0%monthb%
if %minb% EQU 60 set /a minb=%minb%-60 & set /a hourb=%hourb%+1
if %hourb% EQU 24 set /a hourb=%hourb%-24 & set /a dayb=%dayb%+1
if %dayb% EQU 30 set /a dayb=%dayb%-30 & set /a monthb=%monthb%+1
if %monthb% EQU 12 set /a monthb=%monthb%-12 & set /a yearb=%yearb%+1
cls
:: ———————————————————————–
#mode con cols=20 lines=6
title Arbitrary Clock
:time
echo.
echo. %hourb%:%minb%
echo.
echo. %dayb%-%monthb%-%yearb%
echo.
ping -n 2 0.0.0.0 >nul
cls
goto :start
Alright, so as you can see in the new edit to the code, I set the values to the stated at the beginning of this question. Subtracting 10 from the hours, subtracting 1 from the days and months, and subtracting 2000 from the years. I added 30 to the minutes to show the problem right now.
So my system time is 4:40, 1/5/2019. Alright?
The displayed time on the clock is 06:70, 04-00-19.
The desired outcome is 07:10, 04-12-18.
This was edited heavily. Thanks in advance.
You have a fundamental error in your description. When you subtract a number of days/months/years from a date, you are subtracting a date, not a number! For example, if today date is 05/01/2019 (obviously in DD/MM/YYYY format) and you want to subtract 1 month, the result should be 05/12/2018 because you are subtracting a date (1 month). If you subtract a number 1 from the month part, then the result will be 05/00/2019. For this reason, this problem should be solved via the well-known methods to add and subtract dates.
The problem with these methods is that they are valid just for a certain range of dates, and that ranges usually start in 1583. If you want to subtract 2000 from year 2018 and get 18, then such "year 18" is not a valid year in the usual date management methods. For this reason, besides to use the usual methods to manage dates, you also need to complete a couple small adjustments.
I taken the code segments linked in my comment and modified they slightly in order to solve this problem. I completed some tests and it seems to work correctly, but perhaps the method may fail in certain specific range of values.
#echo off
setlocal EnableDelayedExpansion
rem Subtract a number of Days/Months/Years # Hours:Minutes:Seconds from a datetime stamp
rem Antonio Perez Ayala aka Aacini
rem Define the "Date in DDMMYYYY format" To "Julian Day Number" conversion "function"
set "DateToJDN(Date)=( a=1Date, y=a%%10000, a/=10000, m=a%%100, d=a/100-100, a=(m-14)/12, (1461*(y+4800+a))/4+(367*(m-2-12*a))/12-(3*((y+4900+a)/100))/4+d-32075 )"
set /P "stamp1=Enter base timestamp as DD/MM/YYYY HH:MM:SS "
set /P "stamp2=Enter timestamp to subtract in same format: "
set "adjust=0"
for /F "tokens=1-4" %%a in ("%stamp1% %stamp2%") do set "date1=%%a" & set "time1=%%b" & set "date2=%%c" & set "time2=%%d"
if 1%date2:~-4% lss 11600 (
set /A "adjust=1%date2:~-4%+1600"
set "date2=%date2:~0,-4%!adjust:~1!"
set "adjust=1600"
)
set /A "days=!DateToJDN(Date):Date=%date1:/=%! - !DateToJDN(Date):Date=%date2:/=%!, days1600=%DateToJDN(Date):Date=00001600%"
set /A "ss=(((1%time1::=-100)*60+1%-100) - (((1%time2::=-100)*60+1%-100)"
if %ss% lss 0 set /A "ss+=60*60*24, days-=1"
set /A "hh=ss/3600+100, ss%%=3600, mm=ss/60+100, ss=ss%%60+100"
if %days% lss %days1600% set /A days+=days1600, days1600=0
set /A "l=days+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,D=l-(2447*j)/80+100,l=j/11,M=j+2-(12*l)+100,Y=100*(n-49)+i+l+10000+adjust"
if %days1600% equ 0 set /A Y-=1600
echo -----------------------
echo Result: %D:~1%/%M:~1%/%Y:~1% %hh:~1%:%mm:~1%:%ss:~1%
A small example:
Enter base timestamp as DD/MM/YYYY HH:MM:SS 05/01/2019 10:53:45
Enter timestamp to subtract in same format: 01/01/2000 10:10:00
-----------------------
Result: 04/12/0018 00:43:45
PS - I really would like to see a PowerShell solution for this problem. It seems that it would take just a simple and short line of code...
A simpler windows batch option is to call a PowerShell command from within your batch script to manipulate past and future dates.
Below, lines 8 and 9 create and format your arbitrary date.
:: Set the below 3 variables to generate an Arbitrary Clock
:: Use a negative number to subtract (-7), positive number to add (7)
set Altered_Days=-7
set Altered_Months=-10
set Altered_Years=-4
:: The script will merge days and years to determine the arbitrary date and print the Arbitrary date to the screen
set /a Altered_Days=(%Altered_Years%*356)+%Altered_Days%
powershell -command "(((Get-date).AddDays(%Altered_Days%)).AddMonths(%Altered_Months%)).ToString('HH:mm, MM-dd-yyyy')"
:: If you want to capture the value in a variable, use the below line
powershell -command "(((Get-date).AddDays(%Altered_Days%)).AddMonths(%Altered_Months%)).ToString('HH:mm, MM-dd-yyyy')">captureVar && set /p Arbitrary_Clock=<captureVar
echo Arbitrary Clock Prediction && echo %Arbitrary_Clock%
This will enable your batch script to create the end result you are looking for on your Windows 10 OS.
One of the great things about PowerShell is that it can easily be called from the cmd line and a batch script. To do so, enter
powershell -command "the powershell command(s)"
If the PowerShell command calls for quotes, you must use a single quote to avoid ending the PowerShell session. To escape characters, follow batch scripting rules. Batch variables can be read in the PowerShell command, but values created in PowerShell must be redirected for later use in your batch script. This can be done as in line 12 above, or by using PowerShell's Set-Content command to write to a file. I frequently use PowerShell in my batch scripts to manipulate file data.
powershell -command "(Get-Content 'file.txt') -replace 'string','' | Select-String -Pattern 'keep lines with string' -SimpleMatch) -replace 'another string','to somthing different' | Set-Content 'file.txt'"
In the case of adding or subtracting time, PowerShell makes the task easy. And it doesn't require you to create a different script. You can write everything else as batch, use PowerShell commands you find helpful, and save the windows' script as batch.
For detailed explanations on how Get-Date and addDays work, reference:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-date?view=powershell-6
and
https://devblogs.microsoft.com/scripting/adding-and-subtracting-dates-with-powershell/

Get local time from different Timezone using batchfile

I do not want to use any scripting language, but just plain command line commands/scripting.
I can solve this using a (prepared) TZ table (e.g. format: UTC+06:00 + 'TZ name'), then use TZUTIL to collect their resp UTC values and calculate the Timezone's local time (preferably taking DST into account).
I am just hoping that somebody already did this in a more "proper" way. Searched this/other sites, but found nothing so far.
ps: no 'external' tools/etc, since the final batch-file needs to be distributed EMEA-wise.
get the local date and time (wmic)
get the local offset (wmic)
convert the local time to UTC with the help of #2
get the offset of a TZ. (tzutil /l)
convert the result of #3 and #4 not to mention the change of date (this is where it gets complicated).
I think I have not forgotten something? :)
I had a need to obtain time zone information in a specific format from MS Windows systems via a batch file. I could not find what I needed so I developed my own. Thought I would share for others to use. Use the code and adjust as necessary.
#echo off
REM Obtain the ActiveBias value and convert to decimal
for /f "tokens=3" %%a in ('reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v ActiveTimeBias ^| grep -i "ActiveTimeBias"') do set /a abias=%%a
for /f "tokens=3-8" %%n in ('reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v TimeZoneKeyName') do set tzn=%%n %%o %%p %%q %%r 2>NUL
REM Set the + or - sign variable to reflect the timezone offset
IF "%abias:~0,1%"=="-" (set si=+) ELSE (set si=-)
for /f "tokens=1 delims=-" %%t in ('echo %abias%') do set tzc=%%t
REM Calculate to obtain floating points (decimal values)
set /a tzd=100*%tzc%/60
REM Calculate the active bias to obtain the hour
set /a tze=%tzc%/60
REM Set the minutes based on the result of the floating point calculation
IF "%tzd%"=="0" (set en=00 && set si=)
IF "%tzd:~1%"=="00" (set en=00) ELSE IF "%tzd:~2%"=="00" (set en=00 && set tz=%tzd:~0,2%)
IF "%tzd:~1%"=="50" (set en=30) ELSE IF "%tzd:~2%"=="50" (set en=30 && set tz=%tzd:~0,2%)
IF "%tzd:~1%"=="75" (set en=45) ELSE IF "%tzd:~2%"=="75" (set en=45 && set tz=%tzd:~0,2%)
REM Adding a 0 to the beginning of a single digit hour value
IF %tze% LSS 10 (set tz=0%tze%)
REM Display timezone name and offset
echo %tzn% %si%%tz%%en%

Batch Variable Range for %TIME%

For school, I would like to be able to create a batch file that will check what the %TIME% variable is and if it 8:15-9:45, then goto my first period folder 9:45-10:30 to goto second period, etc. I know how to do this if there is a specific time, but not how to set a range of time. Any help would be greatly appreciated! Thanks.
One way is to convert the time into HHMMSS format. Something like this
set timep=%time%
if "%timep:~1,1%" == ":" set timep=0%timep%
set timeval=%timep:~0,2%%timep:~3,2%%timep:~5,2%
Now set the default period to 0
set /a period=0
Since in string form 083000 is between 081500 and 094500, you can just stick to string comparisons without converting to numeric
...
if /i %timeval% geq 103000 set /a period=%period%+1
if /i %timeval% geq 094500 set /a period=%period%+1
if /i %timeval% geq 081500 set /a period=%period%+1
%period% will now hold 0 if the time is less than 0815, 1 if it is between 0815 and 0945 etc.

Batch file setting variable in if/else statement in For Loop

I'm trying to create a batch file that generates a custom AVIsynth script per each file. Right now the batch file is set to execute from within the folder where the video files exist. What I need to do is get the creation time of the file to generate a timecode burn in. I have no problem getting the info I need. However, if the file was created in the afternoon I need it to be in 24hr time. For example, 2pm needs to display as 14.
I have a working if statement that creates a newth variable that adds 12 if need be. However, if it doesn't need it the variable persists. On each subsequent iteration of the loop the variable doesn't change.
My example. I have two files the first was created at 2pm the other at 12pm. The 2pm file is read first and the newth variable becomes 14. So far so good. On the next file the newth variable should become 12 but instead remains 14. How do I fix this?
#Echo Off & CLS
SetLocal EnableDelayedExpansion
For /F %%a In ('dir *.mpg /b') Do (
ECHO Processing "%%a"
echo %%~ta
set time=%%~ta
set th=!time:~11,2!
set tm=!time:~14,2!
set era=!time:~17,2!
echo !era!
if "!era!"=="PM" (
if !th! LSS 12 ( set /a newth=!th!+12 )
) else ( set /a newth=!th!)
echo !newth!
echo //AviSynth Test Script >scripts/%%a.avs
echo DirectshowSource^("%%~fa"^)>>scripts/%%a.avs
echo LanczosResize^(720,400^) >>scripts/%%a.avs
echo ShowSMPTE^(^) >>scripts/%%a.avs
ECHO Back to Console
Pause
)
It's a little messy because I've been using echo for debugging. But hopefully the problem is clear.
Here is a method with Wmic - Wmic is in XP pro and above.
#Echo Off & CLS
SetLocal EnableDelayedExpansion
For /F "delims=" %%a In ('dir *.mpg /b') Do (
ECHO Processing "%%a"
set "file=%cd%\%%a"
set "file=!file:\=\\!"
WMIC DATAFILE WHERE name="!file!" get creationdate|find ".">file.tmp
for /f %%a in (file.tmp) do set dt=%%a
set tm=!dt:~8,2!:!dt:~10,2!:!dt:~12,2!
del file.tmp
echo !tm!
echo //AviSynth Test Script >scripts/%%a.avs
echo DirectshowSource^("%%~fa"^)>>scripts/%%a.avs
echo LanczosResize^(720,400^) >>scripts/%%a.avs
echo ShowSMPTE^(^) >>scripts/%%a.avs
ECHO Back to Console
Pause
)
There are a few problems with your code. The major one is this sequence
if "!era!"=="PM" (
if !th! LSS 12 ( set /a newth=!th!+12 )
) else ( set /a newth=!th!)
With your first filetime "02:xx PM"
th=02, era=PM, so set /a newth=02+12 sets newth=14
With your second filetime "12:xx PM"
th=12, era=PM, so - do nothing, since there's no else action for !th! LSS 12
Hence, newth remains at 14.
So - what's the fix? Since you don't use newth further, we can't say for certain, but it appears you want 24-hour format - 4 digit hhmm.
DANGER, Will Robinson moment number 1:
You are dealing with numbers starring LEADING ZEROES. All well and good except where the value is 08 or 09, which batch bizarrely interprets as OCTAL since it begins 0.
DANGER, Will Robinson moment number 2:
set /a will suppress leading zeroes, so set /a newth=!th! will set newth to 7 for time 07:36 AM - not 07...
So - how to overcome all this?
IF !th!==12 SET th=00
SET th=!th: =0!
if "!era!"=="PM" (set /a newth=1!th!+12
SET newth=!newth:~-2!
) else ( set newth=!th!)
This forces 12 AM to 00 AM and 12 PM to 00 PM
Then replace any spaces with 0 (in case you have leading spaces, not zeroes)
Then, if era is PM, add 100 by stringing 1 before the 2-digit hour number, add 12 and grab the last 2 characters
Otherwise, just use the number in th
Unfortunately, made a little more complicated since you haven't told us whether you use or don't use leading zeroes in your time format. Nevertheless, the incomplete original calculation method is at fault.
DANGER, Will Robinson moment number 3:
time is a MAGIC VARIABLE - and you know what happened to Mickey when he got involved in things better left alone.
If you set time in a batch, then %time% or !time! will return the value you set. If you don't set it, then the value returned will be the system time. Same goes for DATE and a number of similar values (see set /? from the prompt - there's a list at the end)
here's how you can get the time stamp with seconds:
C:\>powershell -command "& {(gwmi -query """select * from cim_datafile where name = 'C:\\file.txt' """).lastModified;}"
C:\>powershell -command "& {(gwmi -query """select * from cim_datafile where name = 'D:\\other.txt' """).creationdate;}"
I've tried with WMIC but still cannot get the time stamp.As you are using Win7 you should have powershell installed by default.

How do I measure execution time of a command on the Windows command line?

Is there a built-in way to measure execution time of a command on the Windows command line?
PowerShell has a cmdlet for this called Measure-Command. You'll have to ensure that PowerShell is available on the machine that runs it.
PS> Measure-Command { echo hi }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 1318
TotalDays : 1.52546296296296E-09
TotalHours : 3.66111111111111E-08
TotalMinutes : 2.19666666666667E-06
TotalSeconds : 0.0001318
TotalMilliseconds : 0.1318
Measure-Command captures the command's output. You can redirect the output back to your console using Out-Default:
PS> Measure-Command { echo hi | Out-Default }
hi
Days : 0
...
As Makotoe commented, Measure-Command returns a TimeSpan object, so the measured time is printed as a bunch of fields. You can format the object into a timestamp string using ToString():
PS> (Measure-Command { echo hi | Out-Default }).ToString()
hi
00:00:00.0001318
If the command inside Measure-Command changes your console text color, use [Console]::ResetColor() to reset it back to normal.
If you want
To measure execution time down to the hundredth of a second in (hh:mm:ss.ff format)
To not have to download and install a resource pack
To look like a huge DOS nerd (who doesn't)
Try copying the following script into a new batch file (e.g. timecmd.bat):
#echo off
#setlocal
set start=%time%
:: Runs your command
cmd /c %*
set end=%time%
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 %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%
if 1%ms% lss 100 set ms=0%ms%
:: Mission accomplished
set /a totalsecs = %hours%*3600 + %mins%*60 + %secs%
echo command took %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total)
Usage
If you put timecmd.bat in a directory in your path, you can call it from anywhere like this:
timecmd [your command]
E.g.
C:\>timecmd pause
Press any key to continue . . .
command took 0:0:1.18
If you want to do output redirection, you can quote the command like this:
timecmd "dir c:\windows /s > nul"
This should handle commands that run from before- to after-midnight, but the output will be wrong if your command runs for 24 hours or more.
Hehe, the most simple solution might be this:
echo %time%
YourApp.exe
echo %time%
This works on every Windows out of the box.
In case of an application using console output, it might be convenient to store the starting time in a temporary variable:
set startTime=%time%
YourApp.exe
echo Start Time: %startTime%
echo Finish Time: %time%
Just a little expansion of the answer from Casey.K about using the Measure-Command from PowerShell:
You can invoke PowerShell from the standard command prompt, like this:
powershell -Command "Measure-Command {echo hi}"
This will eat the standard output, but you can prevent that by adding | Out-Default like this from PowerShell:
Measure-Command {echo hi | Out-Default}
Or from a command prompt:
powershell -Command "Measure-Command {echo hi | Out-Default}"
Of course, you're free to wrap this in a script file *.ps1 or *.bat.
If you are using Windows 2003 (note that windows server 2008 and later are not supported) you can use The Windows Server 2003 Resource Kit, which contains timeit.exe that displays detailed execution stats. Here is an example, timing the command "timeit -?":
C:\>timeit timeit -?
Invalid switch -?
Usage: TIMEIT [-f filename] [-a] [-c] [-i] [-d] [-s] [-t] [-k keyname | -r keyname] [-m mask] [commandline...]
where: -f specifies the name of the database file where TIMEIT
keeps a history of previous timings. Default is .\timeit.dat
-k specifies the keyname to use for this timing run
-r specifies the keyname to remove from the database. If
keyname is followed by a comma and a number then it will
remove the slowest (positive number) or fastest (negative)
times for that keyname.
-a specifies that timeit should display average of all timings
for the specified key.
-i specifies to ignore non-zero return codes from program
-d specifies to show detail for average
-s specifies to suppress system wide counters
-t specifies to tabular output
-c specifies to force a resort of the data base
-m specifies the processor affinity mask
Version Number: Windows NT 5.2 (Build 3790)
Exit Time: 7:38 am, Wednesday, April 15 2009
Elapsed Time: 0:00:00.000
Process Time: 0:00:00.015
System Calls: 731
Context Switches: 299
Page Faults: 515
Bytes Read: 0
Bytes Written: 0
Bytes Other: 298
You can get TimeIt in the Windows 2003 Resource Kit. It's not available for direct download from the Microsoft Download Center, but one can still get it from the archive.org - Windows Server 2003 Resource Kit Tools.
The one-liner I use in Windows Server 2008 R2 is:
cmd /v:on /c "echo !TIME! & *mycommand* & echo !TIME!"
So long as mycommand doesn't require quotes (which screws with cmd's quote processing). The /v:on is to allow for the two different TIME values to be evaluated independently rather than once at the execution of the command.
If you have a command window open and call the commands manually, you can display a timestamp on each prompt, e.g.
prompt $d $t $_$P$G
It gives you something like:
23.03.2009 15:45:50,77
C:\>
If you have a small batch script that executes your commands, have an empty line before each command, e.g.
(empty line)
myCommand.exe
(next empty line)
myCommand2.exe
You can calculate the execution time for each command by the time information in the prompt. The best would probably be to pipe the output to a textfile for further analysis:
MyBatchFile.bat > output.txt
Since others are recommending installing things like freeware and PowerShell, you could also install Cygwin, which would give you access to many basic Unix commands like time:
abe#abe-PC:~$ time sleep 5
real 0m5.012s
user 0m0.000s
sys 0m0.000s
Not sure how much overhead Cygwin adds.
Not quite as elegant as some of the functionality on Unix, but create a cmd file which looks like:
#echo off
time < nul
yourexecutable.exe > c:\temp\output.txt
time < nul
rem on newer windows system you can try time /T
That will display the start and stop times like so:
The current time is: 10:31:57.92
Enter the new time:
The current time is: 10:32:05.94
Enter the new time:
I use freeware called "GS Timer".
Just make a batch file like this:
timer
yourapp.exe
timer /s
If you need a set of times, just pipe the output of timer /s into a .txt file.
You can get it here: Gammadyne's Free DOS Utilities
The resolution is 0.1 seconds.
I'm using Windows XP and for some reason timeit.exe does not work for me. I found another alternative - PTIME. This works very well.
http://www.pc-tools.net/win32/ptime/
Example -
C:\> ptime
ptime 1.0 for Win32, Freeware - http://www.pc-tools.net/
Copyright(C) 2002, Jem Berkes <jberkes#pc-tools.net>
Syntax: ptime command [arguments ...]
ptime will run the specified command and measure the execution time
(run time) in seconds, accurate to 5 millisecond or better. It is an
automatic process timer, or program timer.
C:\> ptime cd
ptime 1.0 for Win32, Freeware - http://www.pc-tools.net/
Copyright(C) 2002, Jem Berkes <jberkes#pc-tools.net>
=== cd ===
C:\
Execution time: 0.015 s
As long as it doesn't last longer than 24hours...
#echo off
set starttime=%TIME%
set startcsec=%STARTTIME:~9,2%
set startsecs=%STARTTIME:~6,2%
set startmins=%STARTTIME:~3,2%
set starthour=%STARTTIME:~0,2%
set /a starttime=(%starthour%*60*60*100)+(%startmins%*60*100)+(%startsecs%*100)+(%startcsec%)
:TimeThis
ping localhost
set endtime=%time%
set endcsec=%endTIME:~9,2%
set endsecs=%endTIME:~6,2%
set endmins=%endTIME:~3,2%
set endhour=%endTIME:~0,2%
if %endhour% LSS %starthour% set /a endhour+=24
set /a endtime=(%endhour%*60*60*100)+(%endmins%*60*100)+(%endsecs%*100)+(%endcsec%)
set /a timetaken= ( %endtime% - %starttime% )
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
echo.
echo Took: %timetaken% sec.
There's also TimeMem (March 2012):
This is a Windows utility which executes a program and displays its
execution time, memory usage, and IO statistics. It is similar in
functionality to the Unix time utility.
Here is a
Postfix timer version:
Usage example:
timeout 1 | TimeIt.cmd
Execution took ~969 milliseconds.
Copy & paste this into some editor like for example Notepad++ and save it as TimeIt.cmd:
:: --- TimeIt.cmd ----
#echo off
setlocal enabledelayedexpansion
call :ShowHelp
:: Set pipeline initialization time
set t1=%time%
:: Wait for stdin
more
:: Set time at which stdin was ready
set t2=!time!
:: Calculate difference
Call :GetMSeconds Tms1 t1
Call :GetMSeconds Tms2 t2
set /a deltaMSecs=%Tms2%-%Tms1%
echo Execution took ~ %deltaMSecs% milliseconds.
endlocal
goto :eof
:GetMSeconds
Call :Parse TimeAsArgs %2
Call :CalcMSeconds %1 %TimeAsArgs%
goto :eof
:CalcMSeconds
set /a %1= (%2 * 3600*1000) + (%3 * 60*1000) + (%4 * 1000) + (%5)
goto :eof
:Parse
:: Mask time like " 0:23:29,12"
set %1=!%2: 0=0!
:: Replace time separators with " "
set %1=!%1::= !
set %1=!%1:.= !
set %1=!%1:,= !
:: Delete leading zero - so it'll not parsed as octal later
set %1=!%1: 0= !
goto :eof
:ShowHelp
echo %~n0 V1.0 [Dez 2015]
echo.
echo Usage: ^<Command^> ^| %~nx0
echo.
echo Wait for pipe getting ready... :)
echo (Press Ctrl+Z ^<Enter^> to Cancel)
goto :eof
^ - Based on 'Daniel Sparks' Version
Depending on the version of Windows you're using, just running bash will put you into Bash mode. This will allow you to use a bunch of commands that are not available on PowerShell directly (like the time command). Timing your command is now as easy as executing:
# The clause <your-command> (without the angle brackets) denotes the command you want to run.
$ time <your-command>
Note: You can easily quit from Bash mode and return back into your mainstream shell by running exit while in Bash mode.
This worked for me perfectly (Windows 10) after trying out other methods (like Measure-Command) which sometimes produce undesired stats. Hope this works for you as well.
An alternative to measure-time is simply "Get-Date". You don't have that hassle with forwarding output and so on.
$start = Get-Date
[System.Threading.Thread]::Sleep(1500)
$(Get-Date) - $start
Output:
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 506
Ticks : 15060003
TotalDays : 1.74305590277778E-05
TotalHours : 0.000418333416666667
TotalMinutes : 0.025100005
TotalSeconds : 1.5060003
TotalMilliseconds : 1506.0003
This is a one-liner which avoids delayed expansion, which could disturb certain commands:
cmd /E /C "prompt $T$$ & echo.%TIME%$ & COMMAND_TO_MEASURE & for %Z in (.) do rem/ "
The output is something like:
14:30:27.58$
...
14:32:43.17$ rem/
For long-term tests replace $T by $D, $T and %TIME% by %DATE%, %TIME% to include the date.
To use this inside of a batch file, replace %Z by %%Z.
Update
Here is an improved one-liner (without delayed expansion too):
cmd /E /C "prompt $D, $T$$ & (for %# in (.) do rem/ ) & COMMAND_TO_MEASURE & for %# in (.) do prompt"
The output looks similar to this:
2015/09/01, 14:30:27.58$ rem/
...
2015/09/01, 14:32:43.17$ prompt
This approach does not include the process of instancing a new cmd in the result, nor does it include the prompt command(s).
In case anyone else has come here looking for an answer to this question, there's a Windows API function called GetProcessTimes(). It doesn't look like too much work to write a little C program that would start the command, make this call, and return the process times.
In the directory where your program is, type notepad mytimer.bat, click 'yes' to create a new file.
Paste the code below, replacing YourApp.exe with your program, then save.
#echo off
date /t
time /t
YourApp.exe
date /t
time /t
Type mytimer.bat in the command line then press Enter.
Here is my method, no conversion and no ms. It is useful to determine encoding durations (limited to 24 hours though):
#echo off
:start
REM Start time storage
set ST=%time%
echo Process started at %ST%
echo.
echo.
REM Your commands
REM Your commands
REM Your commands
:end
REM Start Time Definition
for /f "tokens=1-3 delims=:" %%a in ("%ST%") do set /a h1=%%a & set /a m1=%%b & set /a s1=%%c
REM End Time Definition
for /f "tokens=1-3 delims=:" %%a in ("%TIME%") do set /a h2=%%a & set /a m2=%%b & set /a s2=%%c
REM Difference
set /a h3=%h2%-%h1% & set /a m3=%m2%-%m1% & set /a s3=%s2%-%s1%
REM Time Adjustment
if %h3% LSS 0 set /a h3=%h3%+24
if %m3% LSS 0 set /a m3=%m3%+60 & set /a h3=%h3%-1
if %s3% LSS 0 set /a s3=%s3%+60 & set /a m3=%m3%-1
echo Start : %ST%
echo End : %time%
echo.
echo Total : %h3%:%m3%:%s3%
echo.
pause
my code gives you the running time in milliseconds, up to 24 hrs, it is locale insensitive, and accounts for negative values if code runs through midnight. it uses delayed expansion, and should be saved in a cmd/bat file.
before your code:
SETLOCAL EnableDelayedExpansion
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set t=%%I
set /a t1 = %t:~8,1%*36000 + %t:~9,1%*3600 + %t:~10,1%*600 + %t:~11,1%*60 + %t:~12,1%*10 + %t:~13,1% && set t1=!t1!%t:~15,3%
after your code:
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set t=%%I
set /a t2 = %t:~8,1%*36000 + %t:~9,1%*3600 + %t:~10,1%*600 + %t:~11,1%*60 + %t:~12,1%*10 + %t:~13,1% && set t2=!t2!%t:~15,3%
set /a t2-=t1 && if !t2! lss 0 set /a t2+=24*3600000
if you want running time in HH:mm:ss.000 format, add:
set /a "h=t2/3600000,t2%%=3600000,m=t2/60000,t2%%=60000" && set t2=00000!t2!&& set t2=!t2:~-5!
if %h% leq 9 (set h=0%h%) && if %m% leq 9 (set m=0%m%)
set t2=%h%:%m%:%t2:~0,2%.%t2:~2,3%
ENDLOCAL
variable t2 holds your running time, you can echo %t2% to display it.
This is a comment/edit to Luke Sampson's nice timecmd.bat and reply to
For some reason this only gives me output in whole seconds... which for me is useless. I mean that I run timecmd pause, and it always results in 1.00 sec, 2.00 sec, 4.00 sec... even 0.00 sec! Windows 7. – Camilo Martin Sep 25 '13 at 16:00 "
On some configurations the delimiters may differ. The following change should cover atleast most western countries.
set options="tokens=1-4 delims=:,." (added comma)
The %time% milliseconds work on my system after adding that ','
(*because site doesn't allow anon comment and doesn't keep good track of identity even though I always use same guest email which combined with ipv6 ip and browser fingerprint should be enough to uniquely identify without password)
Another approach with powershell:
#echo off
for /f %%t in ('powershell "(get-date).tofiletime()"') do set mst=%%t
rem some commands
powershell ((get-date).tofiletime() - %mst%)
this will print the execution time in milliseconds.
If you have CMake installed, you can just run following command.
cmake -E time <the_command_to_measure_run_time>
#echo off & setlocal
set start=%time%
REM Do stuff to be timed here.
REM Alternatively, uncomment the line below to be able to
REM pass in the command to be timed when running this script.
REM cmd /c %*
set end=%time%
REM Calculate time taken in seconds, to the hundredth of a second.
REM Assumes start time and end time will be on the same day.
set options="tokens=1-4 delims=:."
for /f %options% %%a in ("%start%") do (
set /a start_s="(100%%a %% 100)*3600 + (100%%b %% 100)*60 + (100%%c %% 100)"
set /a start_hs=100%%d %% 100
)
for /f %options% %%a in ("%end%") do (
set /a end_s="(100%%a %% 100)*3600 + (100%%b %% 100)*60 + (100%%c %% 100)"
set /a end_hs=100%%d %% 100
)
set /a s=%end_s%-%start_s%
set /a hs=%end_hs%-%start_hs%
if %hs% lss 0 (
set /a s=%s%-1
set /a hs=100%hs%
)
if 1%hs% lss 100 set hs=0%hs%
echo.
echo Time taken: %s%.%hs% secs
echo.
The following script uses only "cmd.exe" and outputs the number of milliseconds from the time a pipeline is created to the time that the process preceding the script exits. i.e., Type your command, and pipe the to the script. Example: "timeout 3 | runtime.cmd" should yield something like "2990." If you need both the runtime output and the stdin output, redirect stdin before the pipe - ex: "dir /s 1>temp.txt | runtime.cmd" would dump the output of the "dir" command to "temp.txt" and would print the runtime to the console.
:: --- runtime.cmd ----
#echo off
setlocal enabledelayedexpansion
:: find target for recursive calls
if not "%1"=="" (
shift /1
goto :%1
exit /b
)
:: set pipeline initialization time
set t1=%time%
:: wait for stdin
more > nul
:: set time at which stdin was ready
set t2=!time!
::parse t1
set t1=!t1::= !
set t1=!t1:.= !
set t1=!t1: 0= !
:: parse t2
set t2=!t2::= !
set t2=!t2:.= !
set t2=!t2: 0= !
:: calc difference
pushd %~dp0
for /f %%i in ('%0 calc !t1!') do for /f %%j in ('%0 calc !t2!') do (
set /a t=%%j-%%i
echo !t!
)
popd
exit /b
goto :eof
:calc
set /a t=(%1*(3600*1000))+(%2*(60*1000))+(%3*1000)+(%4)
echo !t!
goto :eof
endlocal
The answer of driblio can be made a little shorter (though not much readable)
#echo off
:: Calculate the start timestamp
set _time=%time%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _started=_hours*60*60*100+_min*60*100+_sec*100+_cs
:: yourCommandHere
:: Calculate the difference in cSeconds
set _time=%time%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _duration=_hours*60*60*100+_min*60*100+_sec*100+_cs-_started
:: Populate variables for rendering (100+ needed for padding)
set /a _hours=_duration/60/60/100,_min=100+_duration/60/100%%60,_sec=100+(_duration/100%%60%%60),_cs=100+_duration%%100
echo Done at: %_time% took : %_hours%:%_min:~-2%:%_sec:~-2%.%_cs:~-2%
::prints something like:
::Done at: 12:37:53,70 took: 0:02:03.55
To the remark of Luke Sampson this version is octal safe, though the task should be completed in 24 hours.
Having Perl installed the hires solution available, run:
C:\BATCH>time.pl "echo Fine result"
0.01063
Fine result
STDERR comes before measured seconds
#!/usr/bin/perl -w
use Time::HiRes qw();
my $T0 = [ Time::HiRes::gettimeofday ];
my $stdout = `#ARGV`;
my $time_elapsed = Time::HiRes::tv_interval( $T0 );
print $time_elapsed, "\n";
print $stdout;
A solution using pure PHP for cmd and one env. variable:
#echo off
setlocal enableextensions
REM set start time env var
FOR /F "tokens=* USEBACKQ" %%F IN (`php -r "echo microtime(true);"`) DO ( SET start_time=%%F )
## PUT_HERE_THE_COMMAND_TO_RUN ##
REM echo elapsed time
php -r "echo 'elapsed: ' . (round(microtime(true) - trim(getenv('start_time')), 2)) . ' seconds' . mb_convert_encoding('
', 'UTF-8', 'HTML-ENTITIES');"
no need for cygwin or non-trusted utilities. Usefull when PHP is locally available
precision and output format can be easily tweaked
the same idea can be ported for PowerShell
Using a sub to return time in hundredths of second
::tiemeit.cmd
#echo off
Setlocal EnableDelayedExpansion
call :clock
::call your_command or more > null to pipe this batch after your_command
call :clock
echo %timed%
pause
goto:eof
:clock
if not defined timed set timed=0
for /F "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /A timed = "(((1%%a - 100) * 60 + (1%%b - 100)) * 60 + (1%%c - 100)) * 100 + (1%%d - 100)- %timed%"
)
goto:eof

Resources