Echo set specific time - windows

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"

Related

Windows batch event reminder for next day

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

How to kill a windows process running longer than 30 minutes

I basically need to achieve two things,
Find all "firefox.exe" processes running on a windows server
Kill the ones that have been running longer than 30 mins
I have bits and pieces, but not sure how to integrate all of it to make it working as a windows service.
What I have so far -
1) Way to find all running firefox process
wmic process get name,creationdate, processid | findstr firefox
2) Way to kill a process based on PID
taskkill /PID 827
What else is left?
Calculate based on creationdate, which PID is running for longer than 30 mins
Use the taskkill command to sequentially kill all the PIDs that fit the above criteria
set this is a service (this I can probably figure out)
It's easy to think, "You can't do that in .bat". I know that was my first reaction. The problem is you need date manipulation which is not directly supported and is non-trivial. But then Ritchie Lawrence comes to the rescue, having done all the hard work of writing the necessary date functions.
The WMI Process class provides CreationDate in UTC format. Win32_OperatingSystem LocalDateTime gives us the current time in UTC format. We need to subtract the maximum lifetime (30 minutes in your case) from LocalDataTime to get the CutOffTime. Then we can use that to filter Process, and finally call terminate (instead of taskkill). Rather than findstr, I use a WMI where filter (which is much faster).
The following code seems to work. As this is KILLING TASKS, you should test this for yourself.
Note: if "%%p" GEQ "0" is used to filter out the 'blank' line at the end of the results of wmic which is not empty but contains a newline character. As we're expecting a number, this seemed a simple and effective test (though maybe there's a better way to handle this).
#echo off
setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
set MaxRunningMinutes=30
set ProcessName=firefox.exe
for /f "usebackq skip=1" %%t in (
`wmic.exe path Win32_OperatingSystem get LocalDateTime`) do (
if "%%t" GEQ "0" set T=%%t)
rem echo !T!
rem echo !T:~,4!/!T:~4,2!/!T:~6,2! !T:~8,2!:!T:~10,2!:!T:~12,2!
rem echo !T:~15,-4! !T:~-4!
set fsec=!T:~15,-4!
set tzone=!T:~-4!
call :DateToSecs !T:~,4! !T:~4,2! !T:~6,2! !T:~8,2! !T:~10,2! !T:~12,2! UNIX_TIME
rem echo !UNIX_TIME!
set /a CutOffTime=UNIX_TIME-MaxRunningMinutes*60
rem echo !CutOffTime!
call :SecsToDate !CutOffTime! yy mm dd hh nn ss
rem echo !yy!/!mm!/!dd! !hh!:!nn!:!ss!
set UTC=!yy!!mm!!dd!!hh!!nn!!ss!.!fsec!!tzone!
rem echo !UTC!
wmic process where "name='%ProcessName%' AND CreationDate<'%UTC%'" call terminate
rem * Alternate kill method. May be useful if /F flag is needed to
rem * to forcefully terminate the process. (Add the /F flag to
rem * taskill cmd if needed.)
rem for /f "usebackq skip=1" %%p in (
rem `wmic process where "name='%ProcessName%' AND CreationDate<'%UTC%'" get processid`) do (
rem if "%%p" GEQ "0" taskkill /PID %%p)
goto :EOF
rem From: http://www.commandline.co.uk/lib/treeview/index.php
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:DateToSecs %yy% %mm% %dd% %hh% %nn% %ss% secs
::
:: By: Ritchie Lawrence, updated 2002-08-13. Version 1.1
::
:: Func: Returns number of seconds elapsed since 1st January 1970 00:00:00
:: for a given calendar date and time of day. For NT4/2000/XP/2003.
::
:: Args: %1 year to convert, 2 or 4 digit (by val)
:: %2 month to convert, 1/01 to 12, leading zero ok (by val)
:: %3 day of month to convert, 1/01 to 31, leading zero ok (by val)
:: %4 hours to convert, 1/01 to 12 for 12hr times (minutes must be
:: suffixed by 'a' or 'p', 0/00 to 23 for 24hr clock (by val)
:: %5 mins to convert, 00-59 only, suffixed by a/p if 12hr (by val)
:: %6 secs to convert, 0-59 or 00-59 (by val)
:: %7 var to receive number of elapsed seconds (by ref)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEEXTENSIONS
set yy=%1&set mm=%2&set dd=%3&set hh=%4&set nn=%5&set ss=%6
if 1%yy% LSS 200 if 1%yy% LSS 170 (set yy=20%yy%) else (set yy=19%yy%)
set /a dd=100%dd%%%100,mm=100%mm%%%100
set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2
set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633
if 1%hh% LSS 20 set hh=0%hh%
if {%nn:~2,1%} EQU {p} if "%hh%" NEQ "12" set hh=1%hh%&set/a hh-=88
if {%nn:~2,1%} EQU {a} if "%hh%" EQU "12" set hh=00
if {%nn:~2,1%} GEQ {a} set nn=%nn:~0,2%
set /a hh=100%hh%%%100,nn=100%nn%%%100,ss=100%ss%%%100
set /a j=j*86400+hh*3600+nn*60+ss
endlocal&set %7=%j%&goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:SecsToDate %secs% yy mm dd hh nn ss
::
:: By: Ritchie Lawrence, updated 2002-07-24. Version 1.1
::
:: Func: Returns a calendar date and time of day from the number of
:: elapsed seconds since 1st January 1970 00:00:00. For
:: NT4/2000/XP/2003.
::
:: Args: %1 seconds used to create calendar date and time of day (by val)
:: %2 var to receive year, 4 digits for all typical dates (by ref)
:: %3 var to receive month, 2 digits, 01 to 12 (by ref)
:: %4 var to receive day of month, 2 digits, 01 to 31 (by ref)
:: %5 var to receive hours, 2 digits, 00 to 23 (by ref)
:: %6 var to receive minutes, 2 digits, 00 to 59 (by ref)
:: %7 var to receive seconds, 2 digits, 00 to 59 (by ref)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
setlocal ENABLEEXTENSIONS
set /a i=%1,ss=i%%60,i/=60,nn=i%%60,i/=60,hh=i%%24,dd=i/24,i/=24
set /a a=i+2472632,b=4*a+3,b/=146097,c=-b*146097,c/=4,c+=a
set /a d=4*c+3,d/=1461,e=-1461*d,e/=4,e+=c,m=5*e+2,m/=153,dd=153*m+2,dd/=5
set /a dd=-dd+e+1,mm=-m/10,mm*=12,mm+=m+3,yy=b*100+d-4800+m/10
(if %mm% LSS 10 set mm=0%mm%)&(if %dd% LSS 10 set dd=0%dd%)
(if %hh% LSS 10 set hh=0%hh%)&(if %nn% LSS 10 set nn=0%nn%)
if %ss% LSS 10 set ss=0%ss%
endlocal&set %7=%ss%&set %6=%nn%&set %5=%hh%&^
set %4=%dd%&set %3=%mm%&set %2=%yy%&goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Using Powershell
The original question was tagged with "batch-file" so I gave the Windows bat answer first. But I wanted to mention killing a named process that has been running longer than 30 minutes is trivial to do with Powershell:
Get-Process firefox |
Where StartTime -lt (Get-Date).AddMinutes(-30) |
Stop-Process -Force
Again this is KILLING TASKS so please be careful. If you're not familiar with Powershell here's the breakdown of the one liner:
Use the Get-Process cmdlet to get the processes that are running on the local computer. Here the name of the process, firefox is passed in. If needed a list of names can be passed, and wildcards can be used.
The process objects returned by Get-Process are piped to Where to filter on the StartTime property. The Get-Date cmdlet is used to get the current date and time as a DateTime type. The AddMinutes method is called to add -30 minutes, returning a DateTime that represents 30 minutes ago. The -lt operator (technically, in this context, it's a switch parameter), specifies the Less-than operation.
The filtered process objects returned by Where are piped to the Stop-Process cmdlet. The -Force parameter is used to prevent the confirmation prompt.
Above I've used the simplified Where syntax introduced in Powershell 3. If you require Powershell 2 compatibility (which is the latest version that runs on Windows XP), then this syntax is required:
Get-Process firefox |
Where { $_.StartTime -lt (Get-Date).AddMinutes(-30) } |
Stop-Process -Force
Here the curly braces enclose a ScriptBlock. $_ is used to explicitly reference the current object.
I believe you're doing some sort of test automation and there are a lot of hanging firefoxes, so in order to kill ALL those who run more than half and hour, do:
foreach ($process in Get-Process firefox*){If((New-TimeSpan -Start $process.StartTime).TotalHours -gt 0.5) {Stop-Process $process.Id -Force}}
It's actually what we're doing.

how to get yesterday's date in a batch file

I know how to get today's date in Windows 7. here is the command that I am using:
%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%
But I want to get yesterday, I do not know how.
If you're limited to just cmd.exe, then the other solutions, despite their size, are probably as good as you'll get. However, modern Windows (such as your Win7) ships with quite a few other tools which can do the job far easier.
Just create a VBScript yester.vbs script as follows:
d = date() - 1
wscript.echo year(d) * 10000 + month(d) * 100 + day(d)
Then you can call it from your cmd script with:
for /f %%a in ('cscript //nologo yester.vbs') do set yesterday=%%a
and the yesterday variable will be created in the form yyyymmdd for you to manipulate however you desire.
Found a script that will work to ensure you get the previous day even if the year or month changes Dos Yesterday Batch.
#echo off
set yyyy=
set $tok=1-3
for /f "tokens=1 delims=.:/-, " %%u in ('date /t') do set $d1=%%u
if "%$d1:~0,1%" GTR "9" set $tok=2-4
for /f "tokens=%$tok% delims=.:/-, " %%u in ('date /t') do (
for /f "skip=1 tokens=2-4 delims=/-,()." %%x in ('echo.^|date') do (
set %%x=%%u
set %%y=%%v
set %%z=%%w
set $d1=
set $tok=))
if "%yyyy%"=="" set yyyy=%yy%
if /I %yyyy% LSS 100 set /A yyyy=2000 + 1%yyyy% - 100
set CurDate=%mm%/%dd%/%yyyy%
set dayCnt=%1
if "%dayCnt%"=="" set dayCnt=1
REM Substract your days here
set /A dd=1%dd% - 100 - %dayCnt%
set /A mm=1%mm% - 100
:CHKDAY
if /I %dd% GTR 0 goto DONE
set /A mm=%mm% - 1
if /I %mm% GTR 0 goto ADJUSTDAY
set /A mm=12
set /A yyyy=%yyyy% - 1
:ADJUSTDAY
if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
REM ** Month 12 falls through
:SET31
set /A dd=31 + %dd%
goto CHKDAY
:SET30
set /A dd=30 + %dd%
goto CHKDAY
:LEAPCHK
set /A tt=%yyyy% %% 4
if not %tt%==0 goto SET28
set /A tt=%yyyy% %% 100
if not %tt%==0 goto SET29
set /A tt=%yyyy% %% 400
if %tt%==0 goto SET29
:SET28
set /A dd=28 + %dd%
goto CHKDAY
:SET29
set /A dd=29 + %dd%
goto CHKDAY
:DONE
if /I %mm% LSS 10 set mm=0%mm%
if /I %dd% LSS 10 set dd=0%dd%
REM Set IIS and AWS date variables
set IISDT=%yyyy:~2,2%%mm%%dd%
set AWSDT=%yyyy%-%mm%-%dd%
#echo off
:: Strip the day of the week from the current date
FOR %%A IN (%Date%) DO SET Today=%%A
:: Parse the date, prefix day and month with an extra leading zero
FOR /F "tokens=1-3 delims=/" %%A IN ("%Today%") DO (
SET Day=0%%A
SET Month=0%%B
SET Year=%%C
)
:: Remove excess leading zeroes
SET Day=%Day:~-2%
SET Month=%Month:~-2%
:: Display the results
SET Day
SET Month
SET Year
:: Convert to Julian date
CALL :JDate %Year% %Month% %Day%
:: Display the result
SET JDate
:: Subtract 1 day
SET /A JPast = JDate - 1
:: Display the result
SET JPast
:: Convert back to "normal" date again
CALL :GDate %JPast%
:: Display the result
::SET GDate=20130121
SET GDate
echo The previous day in form YYYYMMDD is %GDate%
pause
::::::::::::::::::::::::::::::::::::::::::::::::::::::
GOTO:EOF
:JDate
:: Convert date to Julian
:: Arguments : YYYY MM DD
:: Returns : Julian date
::
:: First strip leading zeroes
SET MM=%2
SET DD=%3
IF %MM:~0,1% EQU 0 SET MM=%MM:~1%
IF %DD:~0,1% EQU 0 SET DD=%DD:~1%
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
SET /A Month1 = ( %MM% - 14 ) / 12
SET /A Year1 = %1 + 4800
SET /A JDate = 1461 * ( %Year1% + %Month1% ) / 4 + 367 * ( %MM% - 2 -12 * % Month1% ) / 12 - ( 3 * ( ( %Year1% + %Month1% + 100 ) / 100 ) ) / 4 + %DD% - 32075
SET Month1=
SET Year1=
GOTO:EOF
:GDate
:: Convert Julian date back to "normal" Gregorian date
:: Argument : Julian date
:: Returns : YYYY MM DD
::
:: Algorithm based on Fliegel-Van Flandern
:: algorithm from the Astronomical Almanac,
:: provided by Doctor Fenton on the Math Forum
:: (http://mathforum.org/library/drmath/view/51907.html),
:: and converted to batch code by Ron Bakowski.
::
SET /A P = %1 + 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 GYear = 100 * ( %Q% - 49 ) + %S% + %V%
SET /A GMonth = %U% + 2 - 12 * %V%
SET /A GDay = %T% - 2447 * %U% / 80
:: Clean up the mess
FOR %%A IN (P Q R S T U V) DO SET %%A=
:: Add leading zeroes
IF 1%GMonth% LSS 20 SET GMonth=0%GMonth%
IF 1%GDay% LSS 20 SET GDay=0%GDay%
:: Return value
:: Here you can define the form that you want
SET GDate=%GYear%%GMonth%%GDay%
GOTO:EOF
Here's a solution that creates the earlierday.vbs file on the fly, uses it and deletes it afterwards.
It stores the result in the NewDate variable
This example calculates 1 day ago, but can easily calculate a date further back by changing the value of the Offset variable.
#echo off
set Offset=1
echo d = date() - WScript.Arguments.Item(0) > earlierday.vbs
echo wscript.echo year(d) * 10000 + month(d) * 100 + day(d) >> earlierday.vbs
for /f %%a in ('cscript //nologo earlierday.vbs %Offset%') do set NewDate=%%a
del earlierday.vbs
echo %NewDate%
pause
You could refine this slightly by using %temp%\earlierday.vbs to create the file in the user's temp folder.
Credits to paxdiablo as this is a simple tweak on his earlier post.
EDIT: Here's something with a loop, close to what I actually need it to do. This will take 14 days off today's date and return that date. Then it will keep going back 7 days at a time until it gets to 35 days day ago.
#echo off
SETLOCAL EnableDelayedExpansion
set BackDaysFrom=14
Set BackDaysTo=35
Set BackDaysStep=7
echo d = date() - WScript.Arguments.Item(0) > earlierday.vbs
echo wscript.echo year(d) * 10000 + month(d) * 100 + day(d) >> earlierday.vbs
for /L %%i in (%BackDaysFrom%, %BackDaysStep%, %BackDaysTo%) do (
for /f %%a in ('cscript //nologo earlierday.vbs %%i') do set NewDate=%%a
echo !NewDate!
)
del earlierday.vbs
pause

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

Average timestamp in batch file

so in short my script currently outputs a csv with the log name, time stamp (10:38:52) and the message (Verification: SUCCESS and SendResponse: Response message).
I now need for this script to be able to calculate and output the time difference between the time stamp on the first message and the timestamp on the second message and provide an average at the bottom of the csv.
#echo off
setlocal EnableDelayedExpansion
echo."Location","Date Time","Result","diff" > output2.csv
(
for %%a in (z:\logdir\*.log) do (
for /f "tokens=1,2,3,4,5,6,7,8,9,10 delims=[+]" %%B in ('findstr /g:searchstrings.txt ^< %%a') do (
set var=%%B
set var1=!var:~-6!
echo."%%a","!var1!","%%B","%%F","timetaken"
)
)
) >> output2.csv
the log file contains many entries but this script should and does pull out just the following lines
[20110314T103852][EMVLib][5056][I000000]: Verification: SUCCESS
[20110314T103902][CSV][3232][D000000]: SendResponse: Response message
These search strings are defined by file searchstrings.txt
Thanks for any help on this!
you have to parse the timestamp and calculate the time value in, say, seconds.
This code, assuming this format 20110314T103852 for the passed string in %1, returns the time value in %2
EDIT: I discovered that you cannot pass the string directly, so I have modified the code
:gettime
set hh=!%1:~9,2!
set mm=!%1:~11,2!
set ss=!%1:~13,2!
set /A %2=hh*3600+mm*60+ss
goto :eof
You may then use it to calculate the time difference like this
set t=%%a
call :gettime t t1
...
set t=%%a
call :gettime t t2
set /A deltat=t2-t1
for a more detailed description of the commands used here, check HELP SET and HELP CALL information.
The code of PA shows the idea, but as it's batch there is no simple solution :-)
The getTime function will fail for 14% of the timestamps of a day.
Why? Because batch handles all numbers with leading zeros as octals, so a 08 and a 09 isn't convert to 8 or 9, it simply fails.
There exists a workaround with prefix a 1 and use only the remainder.
set /a "hh=1!var:0,2! %% 100"
08 -> 108 mod 100 -> 8
So the complete batch could look like
#echo off
setlocal EnableDelayedExpansion
#echo off
setlocal EnableDelayedExpansion
echo."Location","Date Time","Result" > output2.csv
set totalVerifyTime=0
set totalVerifyCount=0
(
for %%a in (n.txt) do (
for /f "tokens=1,5 delims=[+]" %%B in (%%a) do (
set timefield=%%B
set timestamp=!timefield:~-6!
set /a "seconds=1!timestamp:~-2!%%100 + ( 1!timestamp:~0,2!%%100 * 60 + 1!timestamp:~2,2!%%100 ) * 60"
if "%%C"==": Verification: SUCCESS" (
set verifyStart=!seconds!
echo."%%a","!timestamp!","%%B","%%C", "!seconds!", "start of verify"
) ELSE (
set /a diff=seconds - verifyStart
echo."%%a","!timestamp!","%%B","%%C", "!seconds!", "!diff!"
set /a totalVerifyTime+=diff
set /a totalVerifyCount+=1
)
)
)
)
set /a "totalAvg=totalVerifyTime/totalVerifyCount"
echo avg = !totalAvg!

Resources