Skip to main content

How to Display Elapsed Time During Script Execution in Batch Script

When running long-duration automation scripts, such as full system backups, massive data migrations, or complex builds, it is helpful to know exactly how long the process took. This information is vital for performance tuning, logging, and meeting Service Level Agreements (SLAs).

In this guide, we will demonstrate how to capture the starting and ending times and calculate the total elapsed time in hours, minutes, and seconds using Batch arithmetic.

The Strategy: Time Slicing

Batch stores the current time in the %TIME% variable (e.g., 14:30:05.12). To calculate the difference, we need to:

  1. Capture the start time.
  2. Capture the end time.
  3. Parse out the HH, MM, and SS components.
  4. Convert everything to "Total Seconds" to perform the subtraction.
  5. Convert the result back into a readable HH:MM:SS format.

Implementation Script

@echo off
setlocal enabledelayedexpansion

:: 1. Capture the Start Time
set "startTime=!TIME!"

echo Script started at: !startTime!
echo Performing long-running task...
echo ------------------------------------------

:: Simulate work (Wait for 5 seconds)
timeout /t 5 /nobreak >nul

echo ------------------------------------------

:: 2. Capture the End Time
set "endTime=!TIME!"
echo Script finished at: !endTime!

:: 3. Parse and Calculate Elapsed Time
call :CalculateElapsed "!startTime!" "!endTime!"

echo Total Execution Time: !elapsedTime!

endlocal
pause
exit /b

:CalculateElapsed
setlocal enabledelayedexpansion

set "start=%~1"
set "end=%~2"

:: Parse Start Time using colon and period/comma delimiters
:: %TIME% format varies by locale: "HH:MM:SS.cc" or "HH:MM:SS,cc" or " H:MM:SS.cc"
:: Replace comma with period to normalize decimal separator
set "start=!start:,=.!"
set "end=!end:,=.!"

:: Parse components using FOR with delimiters
for /F "tokens=1-4 delims=:." %%a in ("!start!") do (
set "S_HH=%%a"
set "S_MM=%%b"
set "S_SS=%%c"
set "S_CC=%%d"
)
for /F "tokens=1-4 delims=:." %%a in ("!end!") do (
set "E_HH=%%a"
set "E_MM=%%b"
set "E_SS=%%c"
set "E_CC=%%d"
)

:: Convert to integers safely
:: Use 1 prefix trick: prepend 1 to avoid octal interpretation of leading zeros,
:: then subtract the matching power of 10.
set /a "S_HH=1!S_HH! - 100"
set /a "S_MM=1!S_MM! - 100"
set /a "S_SS=1!S_SS! - 100"
set /a "S_CC=1!S_CC! - 100"
set /a "E_HH=1!E_HH! - 100"
set /a "E_MM=1!E_MM! - 100"
set /a "E_SS=1!E_SS! - 100"
set /a "E_CC=1!E_CC! - 100"

:: Convert to centiseconds for higher precision
set /a "startTotal=(S_HH * 360000) + (S_MM * 6000) + (S_SS * 100) + S_CC"
set /a "endTotal=(E_HH * 360000) + (E_MM * 6000) + (E_SS * 100) + E_CC"

:: Handle midnight crossover (if end is less than start, add 24 hours)
set /a "diff=endTotal - startTotal"
if !diff! lss 0 set /a "diff+=8640000"

:: Convert back to HH:MM:SS.cc
set /a "hh=diff / 360000"
set /a "remainder=diff %% 360000"
set /a "mm=remainder / 6000"
set /a "remainder=remainder %% 6000"
set /a "ss=remainder / 100"
set /a "cc=remainder %% 100"

:: Pad single digits with leading zeros for display
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!"

endlocal & set "elapsedTime=%hh%h %mm%m %ss%.%cc%s"
exit /b

Parsing the %TIME% Variable

In Batch, %TIME% always returns a string. The format depends on your system locale:

  • Most locales: HH:MM:SS.cc (e.g., 14:30:05.12)
  • Some European locales: HH:MM:SS,cc (comma instead of period)
  • Some locales use a space instead of a leading zero for single-digit hours: 9:05:02.30

Our script handles all of these by normalizing the delimiter and using FOR /F token parsing instead of fixed-position character slicing.

warning

The Leading Zero / Octal Trap: Batch's set /a interprets numbers with a leading 0 as octal. The digits 08 and 09 are invalid in octal and will cause an error. This means that at 8 and 9 o'clock (hours 08, 09), or at minutes/seconds :08 and :09, a naive set /a "var=08" will fail.

Our script uses the "1-prefix" trick: prepend 1 to the two-digit string (making 08 become 108), then subtract 100. Since 108 has no leading zero, it is always treated as decimal. This is more reliable than stripping leading zeros with for /F "delims=0", which fails when the value is 00 (all characters are stripped, leaving an empty string).

Handling Midnight Crossover

If your script starts at 11:59 PM and ends at 12:05 AM, a simple subtraction would result in a negative number. Our script detects this and adds 8,640,000 centiseconds (24 hours) to correct the calculation.

Applications for Elapsed Time

  1. Optimization: Track how long an expensive database query takes before and after adding an index.
  2. Health Checks: If a "Quick Backup" usually takes 5 minutes but suddenly takes 2 hours, you know there is a disk bottleneck or an error.
  3. Logs: Always include the start, end, and duration in your log files for historical auditing.

Best Practices

  1. Log to File: Instead of just echoing the time to the screen, redirect it to a log: echo Elapsed Time: !elapsedTime! >> results.log.
  2. Centiseconds: The %TIME% variable provides centisecond precision (hundredths of a second) in its last component. Our script preserves this precision for more accurate measurements.
  3. Use PowerShell for Complexity: If you need to calculate durations spanning multiple days, Batch math becomes extremely complex. In those cases, use a one-liner powershell -nologo -noprofile -Command "..." to handle the TimeSpan object.

Conclusion

Measuring elapsed time transforms a Batch script from a "blind" execution into a measurable process. By mastering time parsing and the conversion to total seconds, you can provide precise, professional metrics for every task your script performs. This data is the foundation of efficient system administration and performance management.