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

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/

Related

Batch file gives different values based on machine? [duplicate]

I am compressing files using WinZip on the command line. Since we archive on a daily basis, I am trying to add date and time to these files so that a new one is auto generated every time.
I use the following to generate a file name. Copy paste it to your command line and you should see a filename with a Date and Time component.
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.zip
Output
Archive_20111011_ 93609.zip
However, my issue is AM vs PM. The AM time stamp gives me time 9 (with a leading blank space) vs. 10 naturally taking up the two spaces.
I guess my issue will extend to the first nine days, first 9 months, etc. as well.
How do I fix this so that leading zeroes are included instead of leading blank spaces so I get Archive_20111011_093609.zip?
Another solution:
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set datetime=%%I
It will give you (independent of locale settings!):
20130802203023.304000+120
( YYYYMMDDhhmmss.<milliseconds><always 000>+/-<minutes difference to UTC> )
From here, it is easy:
set datetime=%datetime:~0,8%-%datetime:~8,6%
20130802-203023
For Logan's request for the same outputformat for the "date-time modified" of a file:
for %%F in (test.txt) do set file=%%~fF
for /f "tokens=2 delims==" %%I in ('wmic datafile where name^="%file:\=\\%" get lastmodified /format:list') do set datetime=%%I
echo %datetime%
It is a bit more complicated, because it works only with full paths, wmic expects the backslashes to be doubled and the = has to be escaped (the first one. The second one is protected by surrounding quotes).
Extract the hour, look for a leading space, if found replace with a zero;
set hr=%time:~0,2%
if "%hr:~0,1%" equ " " set hr=0%hr:~1,1%
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%.zip
You should search; you can simply replace all spaces with zero set hr=%hr: =0% – jeb Oct 11 '11 at 14:16
So I did:
set hr=%time:~0,2%
set hr=%hr: =0%
Then use %hr% inside whatever string you are formatting to always get a two-digit hour.
(Jeb's comment under the most popular answer worked the best for me and is the simplest. I repost it here to make it more obvious for future users.)
As Vicky already pointed out, %DATE% and %TIME% return the current date and time using the short date and time formats that are fully (endlessly) customizable.
One user may configure its system to return Fri040811 08.03PM while another user may choose 08/04/2011 20:30.
It's a complete nightmare for a BAT programmer.
Changing the format to a firm format may fix the problem, provided you restore back the previous format before leaving the BAT file. But it may be subject to nasty race conditions and complicate recovery in cancelled BAT files.
Fortunately, there is an alternative.
You may use WMIC, instead. WMIC Path Win32_LocalTime Get Day,Hour,Minute,Month,Second,Year /Format:table returns the date and time in a invariable way. Very convenient to directly parse it with a FOR /F command.
So, putting the pieces together, try this as a starting point...
SETLOCAL enabledelayedexpansion
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
SET /A FD=%%F*1000000+%%D*100+%%A
SET /A FT=10000+%%B*100+%%C
SET FT=!FT:~-4!
ECHO Archive_!FD!_!FT!.zip
)
I found the best solution for me, after reading all your answers:
set t=%date%_%time%
set d=%t:~10,4%%t:~7,2%%t:~4,2%_%t:~15,2%%t:~18,2%%t:~21,2%
echo hello>"Archive_%d%"
If AM I get 20160915_ 150101 (with a leading space and time).
If PM I get 20160915_2150101.
#For /F "tokens=1,2,3,4 delims=/ " %%A in ('Date /t') do #(
Set DayW=%%A
Set Day=%%B
Set Month=%%C
Set Year=%%D
Set All=%%D%%B%%C
)
"C:\Windows\CWBZIP.EXE" "c:\transfer\ziptest%All%.zip" "C:\transfer\MB5L.txt"
This takes MB5L.txt and compresses it to ziptest20120204.zip if run on 4 Feb 2012
You can add leading zeroes to a variable (value up to 99) like this in batch:
IF 1%Var% LSS 100 SET Var=0%Var%
So you'd need to parse your date and time components out into separate variables, treat them all like this, then concatenate them back together to create the file name.
However, your underlying method for parsing date and time is dependent on system locale settings. If you're happy for your code not to be portable to other machines, that's probably fine, but if you expect it to work in different international contexts then you'll need a different approach, for example by reading out the registry settings:
HKEY_CURRENT_USER\Control Panel\International\iDate
HKEY_CURRENT_USER\Control Panel\International\iTime
HKEY_CURRENT_USER\Control Panel\International\iTLZero
(That last one controls whether there is a leading zero on times, but not dates as far as I know).
From the answer above, I have made a ready-to-use function.
Validated with french local settings.
:::::::: PROGRAM ::::::::::
call:genname "my file 1.txt"
echo "%newname%"
call:genname "my file 2.doc"
echo "%newname%"
echo.&pause&goto:eof
:::::::: FUNCTIONS :::::::::
:genname
set d1=%date:~-4,4%
set d2=%date:~-10,2%
set d3=%date:~-7,2%
set t1=%time:~0,2%
::if "%t1:~0,1%" equ " " set t1=0%t1:~1,1%
set t1=%t1: =0%
set t2=%time:~3,2%
set t3=%time:~6,2%
set filename=%~1
set newname=%d1%%d2%%d3%_%t1%%t2%%t3%-%filename%
goto:eof
As others have already pointed out, the date and time formats of %DATE% and %TIME% (as well as date /T and time /T) are locale-dependent, so extracting the current date and time is always a nightmare, and it is impossible to get a solution that works with all possible formats since there are hardly any format limitations.
But there is another problem with a code like the following one (let us assume a date format like MM/DD/YYYY and a 12 h time format like h:mm:ss.ff ap where ap is either AM or PM and ff are fractional seconds):
rem // Resolve AM/PM time:
set "HOUR=%TIME:~,2%"
if "%TIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%TIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %DATE:~-4,4%%DATE:~0,2%%DATE:~3,2%_%HOUR:~-2%%TIME:~3,2%%TIME:~6,2%
Each instance of %DATE% and %TIME% returns the date or time value present at the time of its expansion, therefore the first %DATE% or %TIME% expression might return a different value than the following ones (you can prove that when echoing a long string containing a huge amount of such, preferrably %TIME%, expressions).
You could improve the aforementioned code to hold a single instance of %DATE% and %TIME% like this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
But still, the returned values in %DATE% and %TIME% could reflect different days when executed at midnight.
The only way to have the same day in %CURRDATE% and %CURRTIME% is this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Fix date/time midnight discrepancy:
if not "%CURRDATE%" == "%DATE%" if %CURRTIME:~0,2% equ 0 set "CURRDATE=%DATE%"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
Of course the occurrence of the described problem is quite improbable, but at one point it will happen and cause strange unexplainable failures.
The described problem cannot occur with the approaches based on the wmic command as described in the answer by user Stephan and in the answer by user PA., so I strongly recommend to go for one of them. The only disadvantage of wmic is that it is way slower.
Your question seems to be solved, but ...
I'm not sure if you take the right solution for your problem.
I suppose you try to compress each day the actual project code.
It's possible with ZIP and 1980 this was a good solution, but today you should use a repository system, like subversion or git or ..., but not a zip-file.
Ok, perhaps it could be that I'm wrong.
I realise this is a moot question to the OP, but I just brewed this, and I'm a tad proud of myself for thinking outside the box.
Download gawk for Windows at http://gnuwin32.sourceforge.net/packages/gawk.htm .... Then it's a one liner, without all that clunky DOS batch syntax, where it takes six FOR loops to split the strings (WTF? That's really really BAD MAD AND SAD! ... IMHO of course)
If you already know C, C++, Perl, or Ruby then picking-up AWK (which inherits from the former two, and contributes significantly to the latter two) is a piece of the proverbial CAKE!!!
The DOS Batch command:
echo %DATE% %TIME% && echo %DATE% %TIME% | gawk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}"
Prints:
Tue 04/09/2012 10:40:38.25
20120904-104038
Now that's not quite the full story... I'm just going to be lazy and hard-code the rest of my log-file-name in the printf statement, because it's simple... But if anybody knows how to set a %NOW% variable to AWK's output (yeilding the guts of a "generic" now function) then I'm all ears.
EDIT:
A quick search on Stack Overflow filled in that last piece of the puzzle, Batch equivalent of Bash backticks.
So, these three lines of DOS batch:
echo %DATE% %TIME% | awk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}" >%temp%\now.txt
set /p now=<%temp%\now.txt
echo %now%
Produce:
20120904-114434
So now I can include a datetime in the name of the log-file produced by my SQL Server installation (2005+) script thus:
sqlcmd -S .\SQLEXPRESS -d MyDb -e -i MyTSqlCommands.sql >MyTSqlCommands.sql.%now%.log
And I'm a happy camper again (except life was still SOOOOO much easier on Unix).
I prever to use this over the current accepted answer from Stephan as it makes it possible to configure the timestamp using named parameters after that:
for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
It will provide the following parameters:
Day
DayOfWeek
Hour
Milliseconds
Minute
Month
Quarter
Second
WeekInMonth
Year
You can then configure your format like so:
SET DATE=%Year%%Month%%Day%
So you want to generate date in format YYYYMMDD_hhmmss.
As %date% and %time% formats are locale dependant you might need more robust ways to get a formatted date.
Here's one option:
#if (#X)==(#Y) #end /*
#cscript //E:JScript //nologo "%~f0"
#exit /b %errorlevel%
#end*/
var todayDate = new Date();
todayDate = "" +
todayDate.getFullYear() +
("0" + (todayDate.getMonth() + 1)).slice(-2) +
("0" + todayDate.getDate()).slice(-2) +
"_" +
("0" + todayDate.getHours()).slice(-2) +
("0" + todayDate.getMinutes()).slice(-2) +
("0" + todayDate.getSeconds()).slice(-2) ;
WScript.Echo(todayDate);
and if you save the script as jsdate.bat you can assign it as a value :
for /f %%a in ('jsdate.bat') do #set "fdate=%%a"
echo %fdate%
or directly from command prompt:
for /f %a in ('jsdate.bat') do #set "fdate=%a"
Or you can use powershell which probably is the way that requires the less code:
for /f %%# in ('powershell Get-Date -Format "yyyyMMdd_HHmmss"') do set "fdate=%%#"
Adding other options to this list of answers.
you could have replaced empty space with a 0 something like echo %time: =0%
but that is still dependent, move that code to a buddy's PC in some other random place and you'll get funny outputs. So you can incorporate powershell's Get-Date:
for /f "tokens=*" %%i in ('PowerShell -Command "Get-Date -format 'yyyymmdd_HHmmss'"') do echo %%i.zip"
A space is legal in file names. If you put your path and file name in quotes, it may just fly. Here's what I'm using in a batch file:
svnadmin hotcopy "C:\SourcePath\Folder" "f:\DestPath\Folder%filename%"
It doesn't matter if there are spaces in %filename%.

How to permanently delete specific file after specific number of days after running the script in a batch file

I would like to have a little batch file script which will work on Windows XP,7,8 and delete any occurrences of a specific file after a certain amount of time after the script is executed.
I have tried something similar:
forfiles -p "C:\what\ever" -s -m *somefile.pdf* /D -<number of days> /C "cmd /c del #path"
But this isn't what I'm actually looking for as it is deleting files older than a specific time. Any useful advice ?
There are basically three ways to solve this problem:
Keep the Batch file running all the time, delete the file after the desired time complete and restart the process. This is the method used in wOxxOm's answer.
Use Windows Task Scheduler to execute the "delete file" command every N days.
Place a Batch file in Startup folder so it run each time the user log in. The Batch file check if the file must be deleted to do it, calculate the date of the next time and store it in a companion data file. This is the method used in the Batch file below:
.
#echo off
setlocal EnableDelayedExpansion
rem Get today's date arranged as YYYYMMDD
rem (adjust lines below if MM/DD/YYYY is not the current locale date format)
for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
set "MM=%%a" & set "DD=%%b" & set "YYYY=%%c"
)
set "today=%YYYY%%MM%%DD%"
rem Read next date from companion file
set /P nextDate=< NextDate.txt
if %today% lss %nextDate% goto :EOF
rem Delete the file, calculate next date and store it in companion file
del "C:\what\ever\somefile.pdf"
set days=5
set mon=0
for %%a in (31 28 31 30 31 30 31 31 30 31 30 31) do (
set /A mon+=1
set "daysPerMonth[!mon!]=%%a"
)
set /A Ymod4=YYYY %% 4, MM=1%MM% - 100, DD=1%DD% - 100 + days
if %Ymod4% equ 0 set "daysPerMonth[2]=29"
if %DD% gtr !daysPerMonth[%MM%]! set /A DD-=daysPerMonth[%MM%], MM+=1
if %MM% gtr 12 set /A MM=1, YYYY+=1
if %MM% lss 10 set "MM=0%MM%"
if %DD% lss 10 set "DD=0%DD%"
echo %YYYY%%MM%%DD%> NextDate.txt
Note that you must manually create the NextDate.txt file with the first date, although additional code may be inserted in order to manage this initialization step.
Using only the built-in commands:
set days=5
for /L %%T in (1,1,%days%) do timeout 86400
del "C:\what\ever\*somefile.pdf*"
This will pause the execution of the batch file for the given number of days, then it'll delete the file(s).

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.

Batch command date and time in file name

I am compressing files using WinZip on the command line. Since we archive on a daily basis, I am trying to add date and time to these files so that a new one is auto generated every time.
I use the following to generate a file name. Copy paste it to your command line and you should see a filename with a Date and Time component.
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.zip
Output
Archive_20111011_ 93609.zip
However, my issue is AM vs PM. The AM time stamp gives me time 9 (with a leading blank space) vs. 10 naturally taking up the two spaces.
I guess my issue will extend to the first nine days, first 9 months, etc. as well.
How do I fix this so that leading zeroes are included instead of leading blank spaces so I get Archive_20111011_093609.zip?
Another solution:
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set datetime=%%I
It will give you (independent of locale settings!):
20130802203023.304000+120
( YYYYMMDDhhmmss.<milliseconds><always 000>+/-<minutes difference to UTC> )
From here, it is easy:
set datetime=%datetime:~0,8%-%datetime:~8,6%
20130802-203023
For Logan's request for the same outputformat for the "date-time modified" of a file:
for %%F in (test.txt) do set file=%%~fF
for /f "tokens=2 delims==" %%I in ('wmic datafile where name^="%file:\=\\%" get lastmodified /format:list') do set datetime=%%I
echo %datetime%
It is a bit more complicated, because it works only with full paths, wmic expects the backslashes to be doubled and the = has to be escaped (the first one. The second one is protected by surrounding quotes).
Extract the hour, look for a leading space, if found replace with a zero;
set hr=%time:~0,2%
if "%hr:~0,1%" equ " " set hr=0%hr:~1,1%
echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%.zip
You should search; you can simply replace all spaces with zero set hr=%hr: =0% – jeb Oct 11 '11 at 14:16
So I did:
set hr=%time:~0,2%
set hr=%hr: =0%
Then use %hr% inside whatever string you are formatting to always get a two-digit hour.
(Jeb's comment under the most popular answer worked the best for me and is the simplest. I repost it here to make it more obvious for future users.)
As Vicky already pointed out, %DATE% and %TIME% return the current date and time using the short date and time formats that are fully (endlessly) customizable.
One user may configure its system to return Fri040811 08.03PM while another user may choose 08/04/2011 20:30.
It's a complete nightmare for a BAT programmer.
Changing the format to a firm format may fix the problem, provided you restore back the previous format before leaving the BAT file. But it may be subject to nasty race conditions and complicate recovery in cancelled BAT files.
Fortunately, there is an alternative.
You may use WMIC, instead. WMIC Path Win32_LocalTime Get Day,Hour,Minute,Month,Second,Year /Format:table returns the date and time in a invariable way. Very convenient to directly parse it with a FOR /F command.
So, putting the pieces together, try this as a starting point...
SETLOCAL enabledelayedexpansion
FOR /F "skip=1 tokens=1-6" %%A IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
SET /A FD=%%F*1000000+%%D*100+%%A
SET /A FT=10000+%%B*100+%%C
SET FT=!FT:~-4!
ECHO Archive_!FD!_!FT!.zip
)
I found the best solution for me, after reading all your answers:
set t=%date%_%time%
set d=%t:~10,4%%t:~7,2%%t:~4,2%_%t:~15,2%%t:~18,2%%t:~21,2%
echo hello>"Archive_%d%"
If AM I get 20160915_ 150101 (with a leading space and time).
If PM I get 20160915_2150101.
#For /F "tokens=1,2,3,4 delims=/ " %%A in ('Date /t') do #(
Set DayW=%%A
Set Day=%%B
Set Month=%%C
Set Year=%%D
Set All=%%D%%B%%C
)
"C:\Windows\CWBZIP.EXE" "c:\transfer\ziptest%All%.zip" "C:\transfer\MB5L.txt"
This takes MB5L.txt and compresses it to ziptest20120204.zip if run on 4 Feb 2012
You can add leading zeroes to a variable (value up to 99) like this in batch:
IF 1%Var% LSS 100 SET Var=0%Var%
So you'd need to parse your date and time components out into separate variables, treat them all like this, then concatenate them back together to create the file name.
However, your underlying method for parsing date and time is dependent on system locale settings. If you're happy for your code not to be portable to other machines, that's probably fine, but if you expect it to work in different international contexts then you'll need a different approach, for example by reading out the registry settings:
HKEY_CURRENT_USER\Control Panel\International\iDate
HKEY_CURRENT_USER\Control Panel\International\iTime
HKEY_CURRENT_USER\Control Panel\International\iTLZero
(That last one controls whether there is a leading zero on times, but not dates as far as I know).
From the answer above, I have made a ready-to-use function.
Validated with french local settings.
:::::::: PROGRAM ::::::::::
call:genname "my file 1.txt"
echo "%newname%"
call:genname "my file 2.doc"
echo "%newname%"
echo.&pause&goto:eof
:::::::: FUNCTIONS :::::::::
:genname
set d1=%date:~-4,4%
set d2=%date:~-10,2%
set d3=%date:~-7,2%
set t1=%time:~0,2%
::if "%t1:~0,1%" equ " " set t1=0%t1:~1,1%
set t1=%t1: =0%
set t2=%time:~3,2%
set t3=%time:~6,2%
set filename=%~1
set newname=%d1%%d2%%d3%_%t1%%t2%%t3%-%filename%
goto:eof
As others have already pointed out, the date and time formats of %DATE% and %TIME% (as well as date /T and time /T) are locale-dependent, so extracting the current date and time is always a nightmare, and it is impossible to get a solution that works with all possible formats since there are hardly any format limitations.
But there is another problem with a code like the following one (let us assume a date format like MM/DD/YYYY and a 12 h time format like h:mm:ss.ff ap where ap is either AM or PM and ff are fractional seconds):
rem // Resolve AM/PM time:
set "HOUR=%TIME:~,2%"
if "%TIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%TIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %DATE:~-4,4%%DATE:~0,2%%DATE:~3,2%_%HOUR:~-2%%TIME:~3,2%%TIME:~6,2%
Each instance of %DATE% and %TIME% returns the date or time value present at the time of its expansion, therefore the first %DATE% or %TIME% expression might return a different value than the following ones (you can prove that when echoing a long string containing a huge amount of such, preferrably %TIME%, expressions).
You could improve the aforementioned code to hold a single instance of %DATE% and %TIME% like this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
But still, the returned values in %DATE% and %TIME% could reflect different days when executed at midnight.
The only way to have the same day in %CURRDATE% and %CURRTIME% is this:
rem // Store current date and time once in the same line:
set "CURRDATE=%DATE%" & set "CURRTIME=%TIME%"
rem // Resolve AM/PM time:
set "HOUR=%CURRTIME:~,2%"
if "%CURRTIME:~-2%" == "PM" if %HOUR% lss 12 set /A "HOUR+=12"
if "%CURRTIME:~-2%" == "AM" if %HOUR% equ 12 set /A "HOUR-=12"
rem // Fix date/time midnight discrepancy:
if not "%CURRDATE%" == "%DATE%" if %CURRTIME:~0,2% equ 0 set "CURRDATE=%DATE%"
rem // Left-zero-pad hour:
set "HOUR=0%HOUR%"
rem // Build and display date/time string:
echo %CURRDATE:~-4,4%%CURRDATE:~0,2%%CURRDATE:~3,2%_%HOUR:~-2%%CURRTIME:~3,2%%CURRTIME:~6,2%
Of course the occurrence of the described problem is quite improbable, but at one point it will happen and cause strange unexplainable failures.
The described problem cannot occur with the approaches based on the wmic command as described in the answer by user Stephan and in the answer by user PA., so I strongly recommend to go for one of them. The only disadvantage of wmic is that it is way slower.
Your question seems to be solved, but ...
I'm not sure if you take the right solution for your problem.
I suppose you try to compress each day the actual project code.
It's possible with ZIP and 1980 this was a good solution, but today you should use a repository system, like subversion or git or ..., but not a zip-file.
Ok, perhaps it could be that I'm wrong.
I realise this is a moot question to the OP, but I just brewed this, and I'm a tad proud of myself for thinking outside the box.
Download gawk for Windows at http://gnuwin32.sourceforge.net/packages/gawk.htm .... Then it's a one liner, without all that clunky DOS batch syntax, where it takes six FOR loops to split the strings (WTF? That's really really BAD MAD AND SAD! ... IMHO of course)
If you already know C, C++, Perl, or Ruby then picking-up AWK (which inherits from the former two, and contributes significantly to the latter two) is a piece of the proverbial CAKE!!!
The DOS Batch command:
echo %DATE% %TIME% && echo %DATE% %TIME% | gawk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}"
Prints:
Tue 04/09/2012 10:40:38.25
20120904-104038
Now that's not quite the full story... I'm just going to be lazy and hard-code the rest of my log-file-name in the printf statement, because it's simple... But if anybody knows how to set a %NOW% variable to AWK's output (yeilding the guts of a "generic" now function) then I'm all ears.
EDIT:
A quick search on Stack Overflow filled in that last piece of the puzzle, Batch equivalent of Bash backticks.
So, these three lines of DOS batch:
echo %DATE% %TIME% | awk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}" >%temp%\now.txt
set /p now=<%temp%\now.txt
echo %now%
Produce:
20120904-114434
So now I can include a datetime in the name of the log-file produced by my SQL Server installation (2005+) script thus:
sqlcmd -S .\SQLEXPRESS -d MyDb -e -i MyTSqlCommands.sql >MyTSqlCommands.sql.%now%.log
And I'm a happy camper again (except life was still SOOOOO much easier on Unix).
I prever to use this over the current accepted answer from Stephan as it makes it possible to configure the timestamp using named parameters after that:
for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
It will provide the following parameters:
Day
DayOfWeek
Hour
Milliseconds
Minute
Month
Quarter
Second
WeekInMonth
Year
You can then configure your format like so:
SET DATE=%Year%%Month%%Day%
So you want to generate date in format YYYYMMDD_hhmmss.
As %date% and %time% formats are locale dependant you might need more robust ways to get a formatted date.
Here's one option:
#if (#X)==(#Y) #end /*
#cscript //E:JScript //nologo "%~f0"
#exit /b %errorlevel%
#end*/
var todayDate = new Date();
todayDate = "" +
todayDate.getFullYear() +
("0" + (todayDate.getMonth() + 1)).slice(-2) +
("0" + todayDate.getDate()).slice(-2) +
"_" +
("0" + todayDate.getHours()).slice(-2) +
("0" + todayDate.getMinutes()).slice(-2) +
("0" + todayDate.getSeconds()).slice(-2) ;
WScript.Echo(todayDate);
and if you save the script as jsdate.bat you can assign it as a value :
for /f %%a in ('jsdate.bat') do #set "fdate=%%a"
echo %fdate%
or directly from command prompt:
for /f %a in ('jsdate.bat') do #set "fdate=%a"
Or you can use powershell which probably is the way that requires the less code:
for /f %%# in ('powershell Get-Date -Format "yyyyMMdd_HHmmss"') do set "fdate=%%#"
Adding other options to this list of answers.
you could have replaced empty space with a 0 something like echo %time: =0%
but that is still dependent, move that code to a buddy's PC in some other random place and you'll get funny outputs. So you can incorporate powershell's Get-Date:
for /f "tokens=*" %%i in ('PowerShell -Command "Get-Date -format 'yyyymmdd_HHmmss'"') do echo %%i.zip"
A space is legal in file names. If you put your path and file name in quotes, it may just fly. Here's what I'm using in a batch file:
svnadmin hotcopy "C:\SourcePath\Folder" "f:\DestPath\Folder%filename%"
It doesn't matter if there are spaces in %filename%.

How long does a batch file take to execute?

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.

Resources