batch-filedelayedvariableexpansion

Delayed Expansion Inside Loop with Arithmetic Operations on Time Values


I am relatively new to batch files, and I have been trying to get the following timing routine (inspired from Arithmetic operations with HH:MM:SS times in batch file) to work:

set "startTime=%time: =0%"

@rem Removing milliseconds information
set startTime=%startTime:~0,-3%

setlocal EnableDelayedExpansion

for %%i in (1 2 3 4 5) do (

   timeout /T 3 /NOBREAK

   set endTime=!time: =0!
   set endTime=!endTime:~0,-3!

   set /A "ss=(((1%endTime::=-100)*60+1%-100)-(((1%startTime::=-100)*60+1%-100)"
   set /A "hh=ss/3600+100,ss%%=3600,mm=ss/60+100,ss=ss%%60+100"

   @rem Get format in HH:MM:SS (maybe H:MM:SS after midnight.. not tested yet)
   echo Start time: %startTime%
   echo End time: !endTime!

   @rem Issue here: Always get the same output despite delayedExpansion active
   echo Diff time: !ss!

   echo.

   @rem Issue here: Not getting expected values
   echo Elapsed time: !hh:~1!:!mm:~1!:!ss:~1!...
   echo.

)
endlocal

I am not quite sure why the output value for the time difference is always the same despite the delayed expansion. Also, the formatted time does not give me the correct values.

Thanks for your help!


Solution

  • First, thanks for the helpful comments which helped me find a solution to my question. In case it might help someone else, I am posting the solution here.

    As mentioned in the comments, the key was to determine the formatting used on my operating system.

    The code that works for me is below, inspired from https://www.py4u.net/discuss/2286184:

    @rem Check that the format of %TIME% is HH:MM:SS.CS for example 23:59:59.99
    echo "%TIME%"
    
    
    set STARTTIME=%TIME%
    
    @rem convert start time 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)
    
    setlocal EnableDelayedExpansion
    
    for %%i in (1 2 3 4 5) do (
    
       timeout /T 3 /NOBREAK
       
       set ENDTIME=!TIME!
    
       @rem convert ENDTIME to centiseconds
       @rem I found that double-quotes with set /A and numbers are needed inside the for loop
       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 Adjust for cases where timings over multiple days
       if !ENDTIME! LSS %STARTTIME% set set /A DURATION=%STARTTIME%-!ENDTIME!
       
       @rem now break the centiseconds down to hours, 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 Enforce double-digit format
       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 timings
       echo STARTTIME: %STARTTIME% centiseconds
       echo ENDTIME: !ENDTIME! centiseconds
       echo DURATION: !DURATION! in centiseconds
       echo Elapsed time: !DURATIONH!:!DURATIONM!:!DURATIONS!.!DURATIONHS!
    
      
    )
    endlocal