yyyy - wmic path win32_localtime get dayofweek




Setting a windows batch file variable to the day of the week (6)

I have a windows batch file that runs daily. Wish to log data into a file and want to rotate it (i.e. having at most the last 7 days worth of data).

Looked into the commands DATE and DELIMS - Cannot figure out a solution.

Is there a simple solution to create a file name that contains the day of the week i.e. 0 for monday etc.

Or do I have to resort to some better shell script.


%DATE% is not your friend. Because the %DATE% environment variable (and the DATE command) returns the current date using the Windows short date format that is fully and endlessly customizable. One user may configure the system to return 07/06/2012 while another might choose Fri060712. Using %DATE% is a complete nightmare for a BAT programmer.

There are two possible approaches to solve this problem:

  1. You may be tempted to temporarily change the short date format, by changing the locale settings in the registry value HKCU\Control Panel\International\sShortDate, to your recognizable format. Then access %DATE% to get the date in the format you want; and finally restore the format back to the original user format. Something like this

    reg copy "HKCU\Control Panel\International" "HKCU\Control Panel\International-Temp" /f >nul
    reg add "HKCU\Control Panel\International" /v sShortDate /d "ddd" /f >nul
    set DOW=%DATE%
    reg copy "HKCU\Control Panel\International-Temp" "HKCU\Control Panel\International" /f >nul
    

    but this method has two problems:

    • it tampers with a global registry value for its local particular purpouses, so it may interfere with other processes or user tasks that at the very same time query the date in short date format, including itself if run simultaneously.

    • and it returns the three letter day of the week in the local language that may be different in different systems or different users.

  2. use WMIC Win32_LocalTime, that returns the date in a convenient way to directly parse it with a FOR command.

    FOR /F "skip=1" %%A IN ('WMIC Path Win32_LocalTime Get DayOfWeek' ) DO (
      set DOW=%%A
    )
    

    this is the method I recommend.


EDIT: My first answer was wrong for VBScript, now my next try...

Nice idea to use CTRL-Z, but I don't like control characters in a batch file, as it is problematic to copy&paste them.
It's depends of your browser, of your editor, of your ...

You could get a hybrid VBScript/Batch also with normal characters, and "normal" code.

:'VBS/Batch Hybrid
:
:
:'Makes the next line only visible for VBScript ^
a=1_
<1' echo off <nul 

set n=nothing' & goto :'batchCode & REM Jump to the batch code

'VBScript-Part
wscript.echo "VB-Start"
wscript.echo "vb-End"
wscript.quit(0)

'Batch part
:'batchCode
set n=n'& echo Batch-Start
set n=n'& echo two
set n=n'& echo Batch-End
set n=n'& cscript /nologo /E:vbscript vbTest.bat

The trick is to prepend each batch line with set n=n'& it is legal for both, but vbs will ignore the rest of the line, only batch will execute the rest of the line.

The other variant is :'remark ^, this is a remark for both, but for batch this remarks also the next line by the multiline character.
The VbScript sees then a=1<1 the rest of the line is a remark '
The batch sees only <1' echo off <nul, the first redirect from 1' will be override by the second <nul, so it results to only echo off < nul.

The only remaining problem is that you can see the first echo off, as it doesn't work in batch to use the @ after a redirection.

For JScript exists a simpler solution hybrid scripting


I have tried to assemble all solutions in one script at http://www.dostips.com/forum/viewtopic.php?p=37780#p37780.

There is the batch script converting the most popular languages into a batch file (.js, .vbs, .ps1, .wsf, .hta and historical .pl).

It works as follows:

    :: convert filename1.vbs to executable filename1.bat
    cmdize.bat filename1.vbs


few more ways:

1.Robocopy not available in XP but can be downloaded form with win 2003 resource tool kit .Also might depend on localization:

@echo off
setlocal 
for /f "skip=8 tokens=2,3,4,5,6,7,8 delims=: " %%D in ('robocopy /l * \ \ /ns /nc /ndl /nfl /np /njh /XF * /XD *') do (
 set "dow=%%D"
 set "month=%%E"
 set "day=%%F"
 set "HH=%%G"
 set "MM=%%H"
 set "SS=%%I"
 set "year=%%J"
)

echo Day of the week: %dow%
endlocal

2.MAKECAB - works on every windows machine (but creates a small temp file).Function provided by carlos:

@Echo Off


Call :GetDate.Init
Rem :GetDate.Init should be called one time in the code before call to :Getdate
Call :GetDate
Echo weekday:%weekday%

Goto :EOF

:GetDate.Init
Set /A "jan=1,feb=2,mar=3,apr=4,may=5,jun=6,jul=7,aug=8,sep=9,oct=10,nov=11,dec=12"
Set /A "mon=1,tue=2,wed=3,thu=4,fri=5,sat=6,sun=7"
(
Echo .Set InfHeader=""
Echo .Set InfSectionOrder=""
Echo .Set InfFooter="%%2"
Echo .Set InfFooter1=""
Echo .Set InfFooter2=""
Echo .Set InfFooter3=""
Echo .Set InfFooter4=""
Echo .Set Cabinet="OFF"
Echo .Set Compress="OFF"
Echo .Set DoNotCopyFiles="ON"
Echo .Set RptFileName="NUL"
) >"%Temp%\~foo.ddf"
Goto :Eof

:GetDate
Set "tf=%Temp%\~%random%"
Makecab /D InfFileName="%tf%" /F "%Temp%\~foo.ddf" >NUL
For /F "usebackq tokens=1-7 delims=: " %%a In ("%tf%") Do (
Set /A "year=%%g,month=%%b,day=1%%c-100,weekday=%%a"
Set /A "hour=1%%d-100,minute=1%%e-100,second=1%%f-100")
Del "%tf%" >NUL 2>&1
Goto :Eof

3.W32TM - uses command switches introduced in Vista so will not work on windows 2003/XP:

@echo off
setlocal
call :w32dow day_ow
echo %day_ow%
pause
exit /b 0
endlocal
:w32dow [RrnVar]
setlocal

rem :: prints the day of the week
rem :: works on Vista and above


rem :: getting ansi date ( days passed from 1st jan 1601 ) , timer server hour and current hour
FOR /F "tokens=4,5 delims=:( " %%D in ('w32tm /stripchart /computer:localhost  /samples:1  /period:1 /dataonly /packetinfo^|find "Transmit Timestamp:" ') do (
 set "ANSI_DATE=%%D"
 set  "TIMESERVER_HOURS=%%E"
)

set  "LOCAL_HOURS=%TIME:~0,2%"
if "%TIMESERVER_HOURS:~0,1%0" EQU "00" set TIMESERVER_HOURS=%TIMESERVER_HOURS:~1,1%
if "%LOCAL_HOURS:~0,1%0" EQU "00" set LOCAL_HOURS=%LOCAL_HOURS:~1,1%
set /a OFFSET=TIMESERVER_HOURS-LOCAL_HOURS

rem :: day of the week will be the modulus of 7 of local ansi date +1
rem :: we need need +1 because Monday will be calculated as 0
rem ::  1st jan 1601 was Monday

rem :: if abs(offset)>12 we are in different days with the time server

IF %OFFSET%0 GTR 120 set /a DOW=(ANSI_DATE+1)%%7+1
IF %OFFSET%0 LSS -120 set /a DOW=(ANSI_DATE-1)%%7+1
IF %OFFSET%0 LEQ 120 IF %OFFSET%0 GEQ -120 set /a DOW=ANSI_DATE%%7+1


rem echo Day of the week: %DOW% 
endlocal & if "%~1" neq "" (set "%~1=%DOW%") else echo %DOW%

4..bat/jscript hybrid (must be saved as .bat):

 @if (@x)==(@y) @end /***** jscript comment ******
 @echo off
 for /f  %%d in ('cscript //E:JScript //nologo "%~f0"') do echo %%d
 exit /b 0
 *****  end comment *********/
 WScript.Echo((new Date).getDay());

5..bat/vbscript hybrid (must be saved as .bat)

 :sub echo(str) :end sub
echo off
'>nul 2>&1|| copy /Y %windir%\System32\doskey.exe '.exe >nul

'& echo/ 
'& for /f %%w in ('cscript /nologo /E:vbscript %~dpfn0') do echo day of the week %%w
'& echo/
'& del /q "'.exe" >nul 2>&1
'& exit /b

WScript.Echo Weekday(Date)
WScript.Quit

6.powershell can be downloaded from microsoft.Available by default in everything form win7 and above:

@echo off
setlocal
for /f %%d in ('"powershell (Get-Date).Day"') do set dow=%%d

echo day of the week : %dow%
endlocal

7.WMIC already used as an answer but just want to have a full reference.And with cleared <CR>:

@echo off
setlocal
for /f "delims=" %%a in ('wmic path win32_localtime get dayofweek /format:list ') do for /f "delims=" %%d in ("%%a") do set %%d

echo day of the week : %dayofweek%
endlocal

9.Selfcompiled jscript.net (must be saved as .bat):

@if (@X)==(@Y) @end /****** silent line that start jscript comment ******

@echo off
::::::::::::::::::::::::::::::::::::
:::       compile the script    ::::
::::::::::::::::::::::::::::::::::::
setlocal
if exist "%~n0.exe" goto :skip_compilation

set "frm=%SystemRoot%\Microsoft.NET\Framework\"
:: searching the latest installed .net framework
for /f "tokens=* delims=" %%v in ('dir /b /s /a:d /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*"') do (
    if exist "%%v\jsc.exe" (
        rem :: the javascript.net compiler
        set "jsc=%%~dpsnfxv\jsc.exe"
        goto :break_loop
    )
)
echo jsc.exe not found && exit /b 0
:break_loop


call %jsc% /nologo /out:"%~n0.exe" "%~dpsfnx0"
::::::::::::::::::::::::::::::::::::
:::       end of compilation    ::::
::::::::::::::::::::::::::::::::::::
:skip_compilation

"%~n0.exe"

exit /b 0


****** end of jscript comment ******/
import System;
import System.IO;

var dt=DateTime.Now;
 Console.WriteLine(dt.DayOfWeek);

Get the day's name From a date

Adapted from https://technet.microsoft.com/en-us/library/ff730960.aspx:

for /f "delims=" %%d in ('powershell (get-date  %day%/%month%/%year%^).dayofweek') do set dow=%%d

For testing purposes:

@echo off
:...
echo Command line: powershell (get-date  %day%/%month%/%year%).dayofweek
echo Result:
powershell (get-date  %day%/%month%/%year%).dayofweek
for /f "delims=" %%d in ('powershell (get-date  %day%/%month%/%year%^).dayofweek') do set dow=%%d
echo dow=%dow%

Is it possible to embed and execute VBScript within a batch file without using a temporary file?

Note - jump to the UPDATE 2014-04-27 section at the bottom of this answer for the best solution.

I used to think the answer was no. But then DosTips user Liviu discovered that the <SUB> character (Ctrl-Z, 0x1A, decimal 26) has bizare effects when embedded within a batch file. If functions somewhat like a line terminator such that it is possible for batch commands that follow a REM (or a :: remark hack) to execute if they are preceded by Ctrl-Z. http://www.dostips.com/forum/viewtopic.php?p=13160#p13160

This has been confirmed on XP Home Edition sp3, Vista Home Premium sp2 64 bit, and Vista Enterprise sp2 32 bit. I'm assuming it works on other Windows versions.

Note - the code below is supposed to have embedded Ctrl-Z characters. I swear I used to see them on this site when viewed with IE8. But they seem to have been lost from this post somehow and I cannot figure out how to post them anymore. I've replaced the characters with the string <SUB>

::<sub>echo This will execute in batch, but it will fail as vbs.
rem<SUB>echo This will execute in batch, and it is also a valid vbs comment
::'<SUB>echo This will execute in batch and it is also a valid vbs comment

That is the key to a successful batch/vbs hybrid. As long as each batch command is preceded by rem<SUB> or ::'<SUB>, then the vbs engine won't see it, but the batch command will run. Just make sure you terminate the batch portion with an EXIT or EXIT /B. Then the remainder of the script can be normal looking vbs.

You can even have a batch label if needed. :'Label is both a valid vbs comment and a valid batch label.

Here is a trivial hybrid script. (again with <SUB> in place of embedded Ctrl-Z char)

::'<SUB>@cscript //nologo //e:vbscript "%~f0" & exit /b
WScript.Echo "Example of a hybrid VBS / batch file"

Update 2012-04-15

jeb found a solution that avoids the awkward CTRL-Z, but it prints out ECHO OFF at the start and also sets some extraneous variables.

I have found a solution without CTRL-Z that eliminates the extraneous variables and is simpler to comprehend.

Normally the special characters &, |, <, > etc. don't work after a REM statement in batch. But the special characters do work after REM.. I found this nugget of information at http://www.dostips.com/forum/viewtopic.php?p=3500#p3500. A test shows that REM. is still a valid VBS comment. EDIT - based on jeb's comment, it is safer to use REM^ (there is a space after the caret).

So here is a trivial VBS/batch hybrid using REM^ &. The only drawback is it prints REM & at the beginning, whereas jeb's solution prints ECHO OFF.

rem^ &@cscript //nologo //e:vbscript "%~f0" & exit /b
WScript.Echo "Example of a hybrid VBS / batch file"

Here is another trivial example that demonstrates multiple batch commands, including a CALL to a labeled sub-routine.

::' VBS/Batch Hybrid

::' --- Batch portion ---------
rem^ &@echo off
rem^ &call :'sub
rem^ &exit /b

:'sub
rem^ &echo begin batch
rem^ &cscript //nologo //e:vbscript "%~f0"
rem^ &echo end batch
rem^ &exit /b

'----- VBS portion ------------
wscript.echo "begin VBS"
wscript.echo "end VBS"
'wscript.quit(0)

I still like the CTRL-Z solution because it eliminates all extraneous output.

UPDATE 2012-12-17

Tom Lavedas posted a method to conveniently run dynamic VBS from a batch script over at Google Groups: No file VBS hybrid scripting. The method uses mshta.exe (Microsoft HTML Application Host).

His original batch solution relied on an external small VBS.BAT script to execute the VBS within a FOR /F. I modified the syntax slightly to make it convenient to embed directly within any given batch script.

It is quite slow, but very convenient. It is restricted to executing a single line of VBS.

The VBS is written normally, except all quotes must be doubled: A quote enclosing a string must be written as "", and quotes internal to a string must be written as """". Normally the mini script is executed within the IN() clause of a FOR /F. It can be executed directly, but only if stdout has been redirected or piped.

It should work on any Windows OS from XP onward as long as IE is installed.

@echo off
setlocal
:: Define simple batch "macros" to implement VBS within batch
set "vbsBegin=mshta vbscript:Execute("createobject(""scripting.filesystemobject"")"
set "vbsBegin=%vbsBegin%.GetStandardStream(1).write("
set ^"vbsEnd=):close"^)"

:: Get yesterday's date
for /f %%Y in ('%vbsBegin% date-1 %vbsEnd%') do set Yesterday=%%Y
set Yesterday
pause
echo(

:: Get pi
for /f %%P in ('%vbsBegin% 4*atn(1) %vbsEnd%') do set PI=%%P
set PI
pause
echo(

set "var=name=value"
echo Before - %var%
:: Replace =
for /f "delims=" %%S in (
  '%vbsBegin% replace(""%var%"",""="","": "") %vbsEnd%'
) do set "var=%%S"
echo After  - %var%
pause
echo(

echo Extended ASCII:
for /l %%N in (0,1,255) do (

  %=  Get extended ASCII char, except can't work for 0x00, 0x0A.  =%
  %=  Quotes are only needed for 0x0D                             =%
  %=    Enclosing string quote must be coded as ""                =%
  %=    Internal string quote must be coded as """"               =%
  for /f delims^=^ eol^= %%C in (
    '%vbsBegin% """"""""+chr(%%N)+"""""""" %vbsEnd%'
  ) do set "char.%%N=%%~C"

  %=  Display result  =%
  if defined char.%%N (
    setlocal enableDelayedExpansion
    echo(   %%N: [ !char.%%N! ]
    endlocal
  ) else echo(   %%N: Doesn't work :(
)
pause
echo(

:: Executing the mini VBS script directly like the commented code below 
:: will not work because mshta fails unless stdout has been redirected
:: or piped.
::
::    %vbsBegin% ""Hello world"" %vbsEnd%
::

:: But this works because output has been piped
%vbsBegin% ""Hello world"" %vbsEnd% | findstr "^"
pause

UPDATE 2014-04-27

Over at DosTips there is a great compendium of js/vbs/html/hta hybrids and chimeras in cmd/bat. Lots of good stuff from various people.

Within that thread, DosTips user Liviu discovered a beautiful VBS/batch hybrid solution that uses WSF.

<!-- : Begin batch script
@echo off
cscript //nologo "%~f0?.wsf"
exit /b

----- Begin wsf script --->
<job><script language="VBScript">
  WScript.Echo "VBScript output called by batch"
</script></job>

I think this solution is fantastic. The batch and WSF sections are clearly separated by nice headers. The batch code is absolutely normal, without any odd syntax. The only restriction is the batch code cannot contain -->.

Similarly, the VBS code within WSF is absolutely normal. The only restriction is the VBS code cannot contain </script>.

The only risk is the undocumented use of '"%~f0?.wsf"' as the script to load. Somehow the parser properly finds and loads the running .BAT script "%~f0", and the ?.wsf suffix mysteriously instructs CSCRIPT to interpret the script as WSF. Hopefully MicroSoft will never disable that "feature".

Since the solution uses WSF, the batch script can contain any number of independent VBS, JScript, or other jobs that can be selectively called. Each job can even utilize multiple languages.

<!-- : Begin batch script
@echo off
echo batch output
cscript //nologo "%~f0?.wsf" //job:JS
cscript //nologo "%~f0?.wsf" //job:VBS
exit /b

----- Begin wsf script --->
<package>
  <job id="JS">
    <script language="VBScript">
      sub vbsEcho()
        WScript.Echo "VBScript output called by JScript called by batch"
      end sub
    </script>
    <script language="JScript">
      WScript.Echo("JScript output called by batch");
      vbsEcho();
    </script>
  </job>
  <job id="VBS">
    <script language="JScript">
      function jsEcho() {
        WScript.Echo("JScript output called by VBScript called by batch");
      }
    </script>
    <script language="VBScript">
      WScript.Echo "VBScript output called by batch"
      call jsEcho
    </script>
  </job>
</package>