I have this script below to track process time of each part of my script. When I run this in a CMD prompt, it works perfectly, but when put into a .bat, it fails to run. This is also constructed in two IF statements.
Also shout out to #driblio who I got this from.
#echo off
set starttime=%TIME%
set startcsec=%STARTTIME:~9,2%
set startsecs=%STARTTIME:~6,2%
set startmins=%STARTTIME:~3,2%
set starthour=%STARTTIME:~0,2%
set /a starttime=(%starthour%*60*60*100)+(%startmins%*60*100)+(%startsecs%*100)+(%startcsec%)
::Process
set endtime=%time%
set endcsec=%endTIME:~9,2%
set endsecs=%endTIME:~6,2%
set endmins=%endTIME:~3,2%
set endhour=%endTIME:~0,2%
if %endhour% LSS %starthour% set /a endhour+=24
set /a endtime=(%endhour%*60*60*100)+(%endmins%*60*100)+(%endsecs%*100)+(%endcsec%)
set /a timetaken= ( %endtime% - %starttime% )
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
echo.
echo Took: %timetaken% sec.
Read entire set /?
Numeric values are decimal numbers, unless prefixed by 0x for
hexadecimal numbers, and 0 for octal numbers. So 0x12 is the same
as 18 is the same as 022. Please note that the octal notation can
be confusing: 08 and 09 are not valid numbers because 8 and
9 are not valid octal digits.
So echo "%startttime%" could return something like
" 9:08:09.04"
↑↑ invalid in set /a 08
↑↑ invalid in set /a 09
↑↑ valid in set /a 04
Use
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set starttime=%TIME%
rem debugging output echo "%starttime%"
set /A startcsec=1%STARTTIME:~9,2% %% 100
set /A startsecs=1%STARTTIME:~6,2% %% 100
set /A startmins=1%STARTTIME:~3,2% %% 100
set starthour=%STARTTIME:~0,2%
set /a starttime=(%starthour%*60*60*100)+(%startmins%*60*100)+(%startsecs%*100)+(%startcsec%)
rem debugging output set start
::Process
:: pause to ensure that endtime >> starttime
pause
set endtime=%time%
rem debugging output echo "%endtime%"
set /A endcsec=1%endTIME:~9,2% %% 100
set /A endsecs=1%endTIME:~6,2% %% 100
set /A endmins=1%endTIME:~3,2% %% 100
set endhour=%endTIME:~0,2%
if %endhour% LSS %starthour% set /a endhour+=24
set /a endtime=(%endhour%*60*60*100)+(%endmins%*60*100)+(%endsecs%*100)+(%endcsec%)
rem debugging output set end
set /a timetaken= ( %endtime% - %starttime% )
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
echo.
echo Took: %timetaken% sec.
Please note that above code snippet still depends on locale and user preferences. For locale and user preference independent solution, use output from wmic os get localdatetime rather than %time% as follows:
for /F %%G in ('wmic OS get localdatetime /Value ^| find "="') do #set %%G
Then, %localdatetime% would contain something like 20170413030820.447000+120 in (fixed-length) CIM_DATETIME format yyyymmddHHMMSS.mmmmmmsUUU where the fields in the format are
yyyy Four-digit year (0000 through 9999). Your implementation can restrict the supported range. For example, an implementation can
support only the years 1980 through 2099.
mm Two-digit month (01 through 12).
dd Two-digit day of the month (01 through 31). This value must be appropriate for the month. For example, February 31 is not valid.
However, your implementation does not have to check for valid data.
HH Two-digit hour of the day using the 24-hour clock (00 through 23).
MM Two-digit minute in the hour (00 through 59).
SS Two-digit number of seconds in the minute (00 through 59).
mmmmmm Six-digit number of microseconds in the second (000000 through 999999). Your implementation does not have to support
evaluation using this field. However, this field must always be
present to preserve the fixed-length nature of the string.
s Plus sign (+) or minus sign (-) to indicate a positive or negative offset from Coordinated Universal Times (UTC).
UUU Three-digit offset indicating the number of minutes that the originating time zone deviates from UTC. For WMI, it is encouraged,
but not required, to convert times to GMT (a UTC offset of zero).
Related
I am relatively new to batch files, and I have been trying to get the following timing routine (inspired from Arithmetic operations with HH:MM:SS times in batch file) to work:
set "startTime=%time: =0%"
#rem Removing milliseconds information
set startTime=%startTime:~0,-3%
setlocal EnableDelayedExpansion
for %%i in (1 2 3 4 5) do (
timeout /T 3 /NOBREAK
set endTime=!time: =0!
set endTime=!endTime:~0,-3!
set /A "ss=(((1%endTime::=-100)*60+1%-100)-(((1%startTime::=-100)*60+1%-100)"
set /A "hh=ss/3600+100,ss%%=3600,mm=ss/60+100,ss=ss%%60+100"
#rem Get format in HH:MM:SS (maybe H:MM:SS after midnight.. not tested yet)
echo Start time: %startTime%
echo End time: !endTime!
#rem Issue here: Always get the same output despite delayedExpansion active
echo Diff time: !ss!
echo.
#rem Issue here: Not getting expected values
echo Elapsed time: !hh:~1!:!mm:~1!:!ss:~1!...
echo.
)
endlocal
I am not quite sure why the output value for the time difference is always the same despite the delayed expansion. Also, the formatted time does not give me the correct values.
Thanks for your help!
First, thanks for the helpful comments which helped me find a solution to my question. In case it might help someone else, I am posting the solution here.
As mentioned in the comments, the key was to determine the formatting used on my operating system.
The code that works for me is below, inspired from https://www.py4u.net/discuss/2286184:
#rem Check that the format of %TIME% is HH:MM:SS.CS for example 23:59:59.99
echo "%TIME%"
set STARTTIME=%TIME%
#rem convert start time to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
setlocal EnableDelayedExpansion
for %%i in (1 2 3 4 5) do (
timeout /T 3 /NOBREAK
set ENDTIME=!TIME!
#rem convert ENDTIME to centiseconds
#rem I found that double-quotes with set /A and numbers are needed inside the for loop
set /A "ENDTIME=(1!ENDTIME:~0,2!-100)*360000 + (1!ENDTIME:~3,2!-100)*6000 + (1!ENDTIME:~6,2!-100)*100 + (1!ENDTIME:~9,2!-100)"
#rem calculating the duratyion is easy
set /A DURATION=!ENDTIME!-%STARTTIME%
#rem Adjust for cases where timings over multiple days
if !ENDTIME! LSS %STARTTIME% set set /A DURATION=%STARTTIME%-!ENDTIME!
#rem now break the centiseconds down to hours, minutes, seconds and the remaining centiseconds
set /A "DURATIONH=!DURATION! / 360000"
set /A "DURATIONM=(!DURATION! - !DURATIONH!*360000) / 6000"
set /A "DURATIONS=(!DURATION! - !DURATIONH!*360000 - !DURATIONM!*6000) / 100"
set /A "DURATIONHS=(!DURATION! - !DURATIONH!*360000 - !DURATIONM!*6000 - !DURATIONS!*100)"
#rem Enforce double-digit format
if !DURATIONH! LSS 10 set DURATIONH=0!DURATIONH!
if !DURATIONM! LSS 10 set DURATIONM=0!DURATIONM!
if !DURATIONS! LSS 10 set DURATIONS=0!DURATIONS!
if !DURATIONHS! LSS 10 set DURATIONHS=0!DURATIONHS!
#rem Outputing timings
echo STARTTIME: %STARTTIME% centiseconds
echo ENDTIME: !ENDTIME! centiseconds
echo DURATION: !DURATION! in centiseconds
echo Elapsed time: !DURATIONH!:!DURATIONM!:!DURATIONS!.!DURATIONHS!
)
endlocal
I want to add some seconds to the current PC time. But I am a beginner in batch script coding and don't know how to modify the current time by adding some seconds.
This is the code I have so far:
Set "tijd=%time%"
echo %tijd%
echo %time%-%tijd%
pause
But the third command line does not output the expected result of current time increased by some seconds.
Here is a commented batch script to get current time without date and add 30 seconds to this time.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Get current time independent on region (country).
for /F "tokens=4-6 delims=/: " %%I in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do set "CurHour=%%I" & set "CurMinute=%%J" & set "CurSecond=%%K" & goto AddSeconds
rem The second value to add must be less than 60 for this code!
rem The code below adds 30 seconds to current time.
rem As second 08 and second 09 would be interpreted as invalid octal
rem numbers and so interpreted with value 0 in an arithmetic expression,
rem there is inserted the character 1 left to the second value to change
rem the second range to 100 to 159 (or 160 on leap second) and adding 30
rem is done by subtracting 70. The same method is used for the minutes 08
rem and 09 and the hours 08 and 09 on incrementing them by one if that is
rem necessary at all.
:AddSeconds
set "NewHour=%CurHour%"
set "NewMinute=%CurMinute%"
set /A NewSecond=1%CurSecond% - 70
if %NewSecond% LSS 60 goto TimeOutput
set /A NewSecond-=60
set /A NewMinute=1%NewMinute% - 99
if %NewMinute% LSS 60 goto TimeOutput
set /A NewMinute-=60
set /A NewHour=1%NewHour% - 99
if %NewHour% LSS 24 goto TimeOutput
set /A NewHour-=24
rem Before the new time is output, the second, minute and hour values are
rem formatted to have always two digits by first inserting 0 at beginning
rem and next use only the last two characters of the second, minute and
rem hour strings assigned to the three environment variables.
:TimeOutput
set "NewSecond=0%NewSecond%"
set "NewSecond=%NewSecond:~-2%"
set "NewMinute=0%NewMinute%"
set "NewMinute=%NewMinute:~-2%"
set "NewHour=0%NewHour%"
set "NewHour=%NewHour:~-2%"
echo Current time: %CurHour%:%CurMinute%:%CurSecond%
echo The new time: %NewHour%:%NewMinute%:%NewSecond%
endlocal
For the command line to get current time read either this answer written by Compo or third part of my answer on same question.
The Windows command processor cmd.exe has no support for time calculations. For that reason it is necessary on using just internal commands of cmd.exe to add 30 seconds to current time with using several arithmetic expressions and IF conditions.
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 /?
robocopy /?
set /?
setlocal /?
See also:
Single line with multiple commands using Windows batch file for an explanation of & operator.
Microsoft documentation for the Windows Commands
SS64.com - A-Z index of Windows CMD commands
I have a question about a piece of code I am writing.
Set /a 4DgtNum= %Random% %%9999
That's what is being used. I need to know how could I make a "Start at this number end in the range of another" code like start at (I.E 1000 and the max you can go to is 9999, but use any number between that ratio).
#ECHO Off
SETLOCAL enabledelayedexpansion
For %%b IN (#) DO FOR /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="
FOR /L %%x IN (1,1,30000) DO CALL :choosernd&SET /a #!num!+=1
SET #
GOTO :eof
:choosernd
set /a min=1000
set /a max=9999
set /a min=1
set /a max=5
set /a rangesize=max-min+1
SET /a numranges=32767/rangesize
SET /a maxrange=rangesize * numranges-1
:chooseagain
set /a num=%RANDOM%
if %num% gtr %maxrange% GOTO chooseagain
SET /a num=(num %% rangesize) + min
rem ECHO %num%
GOTO :EOF
This question has been asked many times on SO. Here's a generate-and-test routine.
The meat of the matter is the :choosernd routine, where you set your minimum and maximum values.
I overrode your 1000 and 9999 with 1 and 5 for ease of testing.
First, calculate range size. That part should be obvious.
Next - the random-number generator returns %random% in the range 0..32767, so using %random% %% 100 for instance would return 328 numbers in 0..67, but 327 in 68..99. Hence, calculate the number of full ranges (327) available, and the maximum value to obtain an even distribution; (100*327)-1=32699.
Get a random number, but reject any that are greater than the maximum, so reject 32700..32767.
Perform a modulus operation on the chosen, filtered number and add the minimum, giving num
The code before this is simply clearing any variables whose names begin # and then executing the :choosernd routine 30,000 times. Each time, the variable #!num! is incremented, where delayedexpansion (which is explained many. many times on SO - use the search facility) is used to correctly choose a counter.
Then the counter is displayed for verification (the "random" generator is not particularly good)
Note that delayedexpansion is used only in the logging routine - it does not need to be invoked for the :choosernd routine.
Also - note that variablenames may not start with a digit.
When you use the point-click-and-giggle method of executing a batch, the batch window will often close if a syntax-error is found. You should instead open a 'command prompt' and run your batch from there so that the window remains open and any error message will be displayed.
I'm new to batch scripting, so please be lenient with this question. When I'm subtracting 1 from 'TodayDay' variable, the value is not getting updated. Below is the line.
set /a "TodayDay=%TodayDay%-1"
My use case is to find if today's date is less than the 'lastOpenedDate' variable, I want to set the 'lastOpenedDate' to yesterday's
set lastOpenedDate=2017-12-22
IF %TodayYear%-%TodayMonth%-%TodayDay% LSS %lastOpenedDate% (
echo Before Subtraction TodayDay is %TodayDay%
set /a "TodayDay=%TodayDay%-1"
echo After Subtraction TodayDay is %TodayDay%
)
When I ran the above code, The output is:
Before Subtraction TodayDay is 20
After Subtraction TodayDay is 20
I got the other variable values from the below-mentioned code
for /F "skip=1 delims=" %%F in ('
wmic PATH Win32_LocalTime GET Day^,Month^,Year /FORMAT:TABLE
') do (
for /F "tokens=1-3" %%L in ("%%F") do (
set TodayDay=0%%L
set TodayMonth=0%%M
set TodayYear=%%N
)
)
set TodayDay=%TodayDay:~-2%
set TodayMonth=%TodayMonth:~-2%
What am I doing wrong?
You need to search SO using the top bar for delayed expansion. It's #1 FAQ.
change
set /a "TodayDay=%TodayDay%-1"
echo After Subtraction TodayDay is %TodayDay%
)
to
set /a "TodayDay=%TodayDay%-1"
)
echo After Subtraction TodayDay is %TodayDay%
which will make sense once you familiarise yourself with delayed expansion.
Now the next problem you'll run into (which won't show itself until the 8th or 9th of the month) is that in batch a leading 0 means "octal" so - you actually need
set /a "TodayDay=1%TodayDay%-1"
)
set "TodayDay=%TodayDay:~-2"
echo After Subtraction TodayDay is %TodayDay%
which adds 100 to the day number by stringing the 1 in front of the day number, then you need to get the last 2 characters.
I currently have the following code in a batch file Backup.bat on my desktop. it is used to back up an excel spreadsheet file each day and rename it by appending the current date and time. File.xlsx is copied and pasted to a new folder as File Sun-06-24-2012 23.21.46PM.xlsx
Currently the date and time is appended as Sun-06-24-2012 23.21.46PM.xlsx but i would like to have it append as Sun-06-24-2012 11.21.46PM.xlsx using the 12 hour clock rather than 24 hour clock format.
Below is the code i am currently using in Windows XP Professional. Would anyone know how to have the time appended in 12 hour clock format rather than 24 hour clock format as it is currently in the code below.
#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=%%A-%%B-%%C-%%D
)
#For /F "tokens=1,2,3 delims=:,. " %%A in ('echo %time%') do #(
Set Hour=%%A
Set Min=%%B
Set Sec=%%C
Set Allm=%%A.%%B.%%C
)
#For /F "tokens=3 delims=: " %%A in ('time /t ') do #(
Set AMPM=%%A
)
copy "C:\Temp\File.xlsx" "C:\Temp\DailyBackup\File %All% %Allm%%AMPM%.xlsx"
I agree with Joey's comment, I think you are better off with 24 hour format.
Also, your method for getting the date and time will break as soon as the code is transferred to another machine that uses a different date and/or time configuration.
But, here goes anyway...
You should get the entire time string from a single %TIME% expansion. Otherwise you run the risk of getting the hour:min:sec before midnight and the AMPM after midnight.
Put #ECHO OFF at the top, then you don't need to sprinkle # throughout your code.
#echo off
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=%%A-%%B-%%C-%%D
)
For /F "tokens=1,2,3 delims=:,. " %%A in ('echo %time%') do (
set /a "Hour=100%%A%%100"
set Min=%%B
set Sec=%%C
)
if %Hour% geq 12 (
set AMPM=PM
set /a "Hour-=12"
) else set "AMPM=AM"
if %Hour% equ 0 set "Hour=12"
if %Hour% lss 10 set "Hour=0%Hour%"
set "Allm=%Hour%.%Min%.%Sec%%AMPM%"
echo on
copy "C:\Temp\File.xlsx" "C:\Temp\DailyBackup\File %All% %Allm%.xlsx"
Time /t is giving you the time in 24-hour format, presumably because that's the default for your computer's locale.
As time /t doesn't appear to offer any formatting options, probably the easiest thing to do is add an extra section to your batch file to convert the 24-hour clock to 12-hour.
Somewhere under Set Hour=%%A you just need to:
Subtract 12 from the hour if it's more than 12
Change '00' into '12'
For example:
If %Hour% gtr 12 (
Set /a Hour=%Hour%-12
)
If %Hour% == 00 (
Set Hour=12
)
The /a switch on Set tells it that the value to the right of the equals sign is a numerical expression to be evaluated.
This will leave you with no leading zero on the hour if it comes out from 1 to 9. You could get around this with another if statement to add a leading zero back in, or there might be a more elegant approach!