I have a batch file that references the current school-year. At the moment I need to change the line "set SchoolYear=t20172018" manually every year. I've tried to find a more elegant solution, but so far without success. The school-year typically runs from the 1st of august to the 30th of June the following year.
Example:
set PSScript="C:\converter\Powershell\somescript.ps1"
set sourcePath="C:\Converter\Output"
set archivePath="C:\Converter\Archive"
set logPath="C:\Converter\Log"
set SchoolYear=t20172018
Rem # Uploading data
Powershell.exe -executionpolicy remotesigned -Command "& '%PSScript%' '%sourcePath%' '%archivePath%' '%logPath%' '%SchoolYear%'"
Is it possible to have the batch file automatically change the 'set schoolyear=t20XX20XX' on the 1st of august every year?
as you explicitely asked for a batch solution:
#echo off
setlocal
for /f "tokens=2 delims==" %%a in ('wmic os get localdatetime /value^|find "="') do set dt=%%a
set y=%dt:~0,4%
set d=%dt:~4,4%
if "%d%" lss "0801" set /a y -= 1
set /a ny=y+1
set schoolyear=t%y%%ny%
echo %schoolyear%
using wmic might be more complicated than using %date%, but it's independent of locale settings.
Note: if is comparing strings here, not dates, but as we got the date in MMDD format, we can easily compare "dates"
This should do the job:
SET "check_date=%DATE:~0,2%"
SET "check_date=%DATE:~3,-5%%check_date%"
SET "current_year=%DATE:~6%"
SET /A "next_year=%current_year%+1"
SET /A "last_year=%current_year%-1"
IF "%check_date%" GEQ "0801" (SET "SchoolYear=t%current_year%%next_year%") ELSE (SET "SchoolYear=t%last_year%%current_year%")
The date scheme is DD.MM.YYYY, if the scheme on your machine is MM/DD/YYYY you need to adjust the 2nd line to: SET "check_date=%check_date%%DATE:~3,-5%"
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%.
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.
I searched this site for my question, but I didn't find a solution to my problem.
The system gives a random number for the player and for the computer, from 2 to 12.
This has 3 parts, if X bigger than Y, if X lesser than Y, and when X is same as Y.
When I start the .bat, it works great, I choose Play Game, I enter the Bet (20 for example), but when I start this process, the window closes, and I can't read what it wrote. I can see some flashing text, I have seen 'Your' and 'syntax', but it disappears very fast.
I'm really sure it worked, because when I delete the 3 if if if things, it shows my money, bet, stats and everything, and I can even decrease or increase it with 'cheats' I wrote.
So, here it is:
set /p setbet=Please type a number to select bet:
if "%setbet%"=="1" set bet=20
if "%setbet%"=="2" set bet=50
if "%setbet%"=="3" set bet=100
if "%setbet%"=="4" set bet=150
if "%setbet%"=="5" set bet=200
if "%setbet%"=="6" set bet=250
if "%setbet%"=="7" set bet=300
echo.
echo Your bet is %bet%.
echo.
pause
cls
set /a money-=bet
set /a playernum=%random% %%12 +2
set /a enemynum=%random% %%12 +2
echo.
echo You roll: %playernum%
echo Enemy rolls: %enemynum%
echo.
if %playernum% LSS %enemynum%
(
echo Enemy wins. Please try again.
echo Your current money is %money%.
echo You lost %bet% money.
echo.
pause
goto INTRO
)
if %enemynum% LSS %playernum%
(
set /a money+=bet*2
echo You win.
echo Your current money is %money%.
echo You won %bet% money.
echo.
pause
goto INTRO
)
if %enemynum% EQU %playernum%
(
set /a money+=bet
echo It's a tie.
echo You won the bet (%bet%), but your money didn't changed.
echo Your money is now %money%.
echo.
pause
goto INTRO
Thank you!
1) You forgot to close your last parenthesis
2) The syntax error is here :
if %enemynum% EQU %playernum%
(
It should be : if %enemynum% EQU %playernum% (
3) The value of the money variable will be wrong when displayed.
It's caused by the two facts:
-> Inside a FOR or a IF, the variables are "expanded" before and not during command execution. ( expanded = the variable is remplaced by its value )
In order to change the value of a variable and use it in the same loop, you should use the delayed expression.
You must write SETLOCAL ENABLEDELAYEDEXPANSION at the beginning of your code and the variable whose expansion should be delayed should be surrounded by exclamation marks instead of percent signs.
So echo Your current money is %money%. become echo Your current money is !money!.
4) You must escape your parenthesis in case of tie :
echo You won the bet ^(%bet%^) but your money didn't changed.
5) You didn't put a label INTRO, so your goto INTRO will fail
you should search for delayed expansion (setlocal enabledelayedexpansion) and count your brackets: every opening bracket needs a closing one (there are exceptions I know, but not here). The opening bracket after if must be on the same line like if. The if parser will stop here: %bet%) because this is the first closing bracket after the last opening.
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)