batch file Subtracting hour current time on Windows - datetime

I need to subtract, for example, 1 hour from current time in a .bat file on Windows 7.
I do it like this.
set day=%date:~0,2%
set month=%date:~-7,2%
set year=%date:~-4,4%
:: ———————————————————————–
set hour=%time:~0,2%
set /A hour= hour - 1
if %hour% lss 0 set hour=23
if %hour% lss 10 set hour=0%hour%
echo %year%-%month%-%day% %hour%:00
But the problem, it is get consistence when the subtracting results a day before on a month before. For example, this date, 2016-03-01 00:05 I get 2016-03-01 23:05. I need to get 2016-02-29 23:05
I found several batch script to subtract one day, but nothing with hours or minutes.

It's not completely Batch, but I find that there are so many exceptions and special cases, that it's not worth it re-coding everything in Batch, especially when it's been done before. I like to just invoke Powershell from a batch file, like this.
for /f "delims=" %%a in ('"powershell [DateTime]::Now.AddHours(-1).ToString('yyyy-MM-dd HH:mm')"') do echo %%a
Output will be something like: 2016-10-18 02:05

Batch files are not good in date/time operations. Spend much time with similar issues, I can recommend to use external tool such (as window port of unix 'date' command for example) and perform any operations on timestamps.

Related

Get hour without space %time:~0,2% [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%.

Create a batch file to load a webpage when the date and time are correct

I am trying to get a webpage to load when the date and time are correct. The code I have come up with is:
#echo off
:repeat
set CurrentTime=%time:~0,2%.%time:~3,2%
set CurrentDate=%date:/=-%
echo.
echo %CurrentDate% %CurrentTime%
echo.
IF %CurrentTime% == Tue 08-04-2014 13.04 goto load
timeout /t 1 >nul
goto repeat
:load
start/MAX iexplore.exe"" "http://www.youtube.com.au"
timeout /t 6 >nul
It will work if I remove the CurrentDate and the date from the IF statement but it won't if I don't. I do need the date and time to work.
Thanks.
IF "%date% %Time%"=="Tue 08-04-2014 13.04" goto load
shoud work for you. You need to use the "quotes" to group the string as a single entity, otherwise IF has no way of telling whether the == is a part of the string to be compared or it's the comparison operator. (and that assumes that your date format is Tue 08-04-2014 and time is 13.04)
Aditionally to the solution that Magoo has posted, note that %DATE% returns the current date using the short date format that is fully and endlessly customizable by the users. One user may configure its system to return Tue 08/04/2014 and another user may choose Apr8th14. It's a complete nightmare for a BAT programmer. Even in the same computer. This is also true for the ~t modifier when expanding a variable containing a filename.
There are several solutions, google a bit to find them. The easiest in my opinion is to use WMIC
WMIC Path Win32_LocalTime Get Day,Hour,Minute,Month,Second,Year /Format:table
returns the date in a convenient way to directly parse with a FOR command.
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 currentdate=%%F*10000+%%D*100+%%A
)
IF "%currentdate"=="20140408" goto load
You can also use a scheduled task if that suits the reason for you wanting to load the page.

PowerShell script with specific date/time range

I am trying to run a powershell script for exchange 2010 to pull information from a specific date/time range.
example: show me amount of received emails from monday-friday time range 6am-11pm
get-messagetrackinglog -resultsize unlimited -Recipient TEST#TEST.COM -Server EXCHANGE -Start "3/4/2013 6:00:00 AM" -End "3/6/2013 23:00:00 PM" | select messageid -unique | measure
but I would like to make the date range not so static. so If i run the script at 11pm on Friday night, every week, how can i get it to do this query for the last 5 days.
I was trying adding in (get-date).adddays(-5) but I can't figure out how to add that in.
any help will be greatly appreciated.
Try this
for($i=-4,$i -lt 0,$i++){
$start = (get-date -hour 6).adddays($i);
$end = (get-date -hour 23).adddays($i);
Write-host $start.DayoftheWeek (get-messagetrackinglog -resultsize unlimited -Recipient TEST#TEST.COM -Server EXCHANGE -Start $start -End $end | select messageid -unique | measure).count
}
The get-messagetrackinglog cmdlet only takes a single argument for -start and -end, so you can't specify that in a single command.
You can run 5 separate queries of the messagetracking logs from 6AM-11PM, each on different days and aggregate those results together, or you can do one query for all the logs from 6AM on the first day to 11PM on the last day, then filter out the ones that are timestamped between 11PM and 6AM in the interim days.
Just trying to answer the part about the past date and hour and assuming you are running this at 11pm but want to go back to 6am (17hrs diff)...
Maybe use something like:
$past=(Get-Date).adddays(-5).addhours(-17)
And then try
-start $past -end (get-date)

Modify batch script to also get Hours and Minutes from %currentdate%

I need to modify a Windows batch file that was written by a developer who has since quit. Here's part of what's already there:
set date/t=%currentdate%
for /f "tokens=2-4 delims=/ " %%a in ('date/t') do (
set fmonth=%%a) & (set fdate=%%b) & (set fyear=%%c)
I kinda, barely understand how/why this works, and it does work as designed. If run this today, fmonth is 08, fdate is 17, and fyear if 2012. But what I also need out of this is hours and seconds. I have been guessing and googling now for way too long, and I need professional help.
Any pointers?
Thanks!
The rene answer will not work in all locales. Some use comma, some use period as the decimal point. Plus the solution can be condensed to a single FOR statement. The following should work in all locales. The fractional seconds are actually centiseconds (1/100), not milliseconds (1/1000).
for /f "tokens=1-4 delims=:.," %%A in ("%time%") do (
set fhour=%%A
set fmin=%%B
set fsec=%%C
set fcsec=%%D
)
If you want to do mathematical computations with the values then you have additional work to do. Values less than 10 will by zero prefixed, which might not seem like a problem. But SET treats any number that is zero prefixed as octal notation, and 08 and 09 are not valid octal digits.
There are a few ways to strip off the leading zero, but the most convenient is to use a bit of math. Simply prefix the value with 100 and then take the modulous 100 (remainder after dividing by 100). All the assignments can be done with a single SET /A statement.
for /f "tokens=1-4 delims=:.," %%A in ("%time%") do set /a "fhour=100%%A%%100, fmin=100%%B%%100, fsec=100%%C%%100, fcsec=100%%D%%100"
split based on %time%
set time=%time%:
for /f "tokens=1-3,* delims=:" %%k in ("%time%") do (set fhour=%%k) & (set fminute=%%l) & (set fsecfrac=%%m)
for /f "tokens=1-3,* delims=," %%k in ("%fsecfrac%") do (set fsecond=%%k) & (set fmsec=%%l)

Schedule Task : 6 months from now

I'm tryin' to find a way (from a batch file) that I can use to create a scheduled task that will execute 6 months from now. I've looked all over the net, and I'll I've come across is AT and SCHTASKS that will schedule the task monthly ..
I'm looking for a solution that will execute this task every 6 months.
I know this will require some time/date manipulation .. finding the month (number of month) and then adding 6 to it; once it passes '12' it goes back to 1 etc .. Then lining those numbers up with the months name, and using SCHTASKS or AT to schedule the task.
I know how to use SCHTASKS to schedule a task from a batch file; I just need the code to find the month, add 6 to it, grab the months name in 6 months time, and put that into a variable so I can parse it into the SCHTASKS.
I hope this all makes sense.
My english is not so great.
TIA,
Greg
Thanks to everyone who replied, and offered suggestions. I slept on it, woke up with the flu, and had a brainwave. Funny how things work out. I know this is overkill, and someone will come up with a better suggestion, but here goes anyway ..
REM Grab month number and put into variable
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
REM Six months from now
set /a addmm=%mm% + 6
if %addmm% gtr 6 (set /a sixmonths=%addmm% - 12)
REM Determine month name
if %sixmonths%==1 (set monthname=JAN)
if %sixmonths%==2 (set monthname=FEB)
if %sixmonths%==3 (set monthname=MAR)
if %sixmonths%==4 (set monthname=APR)
if %sixmonths%==5 (set monthname=MAY)
if %sixmonths%==6 (set monthname=JUN)
if %sixmonths%==7 (set monthname=JUL)
if %sixmonths%==8 (set monthname=AUG)
if %sixmonths%==9 (set monthname=SEP)
if %sixmonths%==10 (set monthname=OCT)
if %sixmonths%==11 (set monthname=NOV)
if %sixmonths%==12 (set monthname=DEC)
REM Schedule Task
schtasks /create /TN TuneUpReminder /RU system /TR TuneUpReminder.bat /SC MONTHLY /M %monthname%
Why not use the Windows Scheduler?
Most of the information you need is included in this article: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/schtasks.mspx?mfr=true
You can use the monthly setting, with a value of 6 surely?
Here's a crazy idea: in case you want this script on a server (which isn't rebooted), you could write a batch file which waits for six months and then executes the given program. To wait for a specific number of seconds you could abuse the 'ping' command, like this:
ping -n %SECS% localhost > NUL
This command will effectively pause for %SECS% seconds and then return. To wait for six months, simply wait for something like (365 / 2) * 24 * 60 * 60 seconds.
Here's a little batch file which implements this idea:
#echo off
set CMD=echo Half a year elapsed
set /a SECS_IN_HALF_A_YEAR=365 / 2 * 24 * 60 * 60
loop_start:
ping -n %SECS_IN_HALF_A_YEAR% localhost > NUL
%CMD%
goto loop_start
I'm not saying it's pretty, but I thought it's a funky idea. Maybe some food for thought. :-)
you can download coreutils for windows . Then use date command like this
C:\test>gnu_date "+%Y%m%d" -d "6 months"
20110404
(it is renamed to gnu_date.exe )
I have not played with schtasks, but depending on what format of date it uses, you can change the parameters to suit schtasks
C:\test>gnu_date "+%Y-%m-%d" -d "6 months"
2011-04-04
If you need time as well
C:\test>gnu_date "+%Y-%m-%d-%H:%M:%S" -d "6 months"
2011-04-04-18:12:35
Use a for loop to save the date to a variable as desired. then pass it to schtasks for scheduling
Since Greg's answer made me cry inside, here is some array like syntax:
for /F "tokens=%sixmonths%" %%A IN ("JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC") DO set monthname=%%A
And since there’s always more than one way to skin a bat[ch]?
set /a sixmonths=%sixmonths% * 4
set months=666 JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
setlocal ENABLEDELAYEDEXPANSION
set monthname=!months:~%sixmonths%,3!
REM Optional: setlocal DISABLEDELAYEDEXPANSION

Resources