21

我有一个每天运行的 Windows 批处理文件。希望将数据记录到文件中并希望对其进行轮换(即最多具有最近 7 天的数据)。

查看命令DATE-DELIMS无法找出解决方案。

是否有一个简单的解决方案来创建一个包含星期几的文件名,即 0 表示星期一等。

还是我必须求助于一些更好的 shell 脚本。

4

17 回答 17

32

%DATE%不是你的朋友。因为%DATE%环境变量(和命令)使用完全且无限可定制的 Windows短日期格式DATE返回当前日期。一位用户可能会将系统配置为返回 07/06/2012,而另一位用户可能会选择 Fri060712。对于 BAT 程序员来说,使用是一场彻头彻尾的噩梦。%DATE%

有两种可能的方法来解决这个问题:

  1. 您可能想通过将注册表值中的区域设置更改HKCU\Control Panel\International\sShortDate为您可识别的格式来临时更改短日期格式。然后访问%DATE%以您想要的格式获取日期;最后将格式恢复为原始用户格式。像这样的东西

    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
    

    但是这种方法有两个问题:

    • 它会篡改其本地特定目的的全局注册表值,因此它可能会干扰同时以短日期格式查询日期的其他进程或用户任务,如果同时运行,则包括其自身。

    • 它以本地语言返回一周中的三个字母天,在不同的系统或不同的用户中可能会有所不同。

  2. 使用WMIC Win32_LocalTime,它以方便的方式返回日期,以便使用FOR命令直接解析它。

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

    这是我推荐的方法。

于 2012-07-06T18:19:02.830 回答
15

还有几种方法:

1. Robocopy在 XP 中不可用,但可以使用 win 2003 资源工具包下载表格。也可能取决于本地化:

@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 - 适用于每台 Windows 机器(但会创建一个小临时文件)。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 - 使用 Vista 中引入的命令开关,因此不适用于 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 混合(必须另存为.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 混合 (必须另存为.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可以从microsoft下载。win7及以上版本默认可用

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

echo day of the week : %dow%
endlocal

7. WMIC已经用作答案,但只想有一个完整的参考。并清除<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.自编译jscript.net(必须另存为.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);
于 2013-12-04T22:56:17.480 回答
6
@ECHO OFF
REM GET DAY OF WEEK VIA DATE TO JULIAN DAY NUMBER CONVERSION
REM ANTONIO PEREZ AYALA
REM GET MONTH, DAY, YEAR VALUES AND ELIMINATE LEFT ZEROS
FOR /F "TOKENS=1-3 DELIMS=/" %%A IN ("%DATE%") DO SET /A MM=10%%A %% 100, DD=10%%B %% 100, YY=%%C
REM CALCULATE JULIAN DAY NUMBER, THEN DAY OF WEEK
IF %MM% LSS 3 SET /A MM+=12, YY-=1
SET /A A=YY/100, B=A/4, C=2-A+B, E=36525*(YY+4716)/100, F=306*(MM+1)/10, JDN=C+DD+E+F-1524
SET /A DOW=(JDN+1)%%7

DOW 为 0 表示周日,1 表示周一,以此类推。

于 2012-07-07T01:34:29.347 回答
4

我认为我的第一个答案给出了正确的星期几作为 0 到 6 之间的数字。但是,由于您没有说明为什么这个答案没有给出您想要的结果,我只能猜测原因。

下面的批处理文件每天创建一个日志文件,名称中有一个数字,0=星期日,1=星期一等...程序假设echo %date%以 MM/DD/YYYY 格式显示日期;如果不是这种情况,只需更改for命令中 mm 和 dd 变量的位置。

@echo off
for /F "tokens=1-3 delims=/" %%a in ("%date%") do set /A mm=10%%a %% 100, dd=10%%b %% 100, yy=%%c
if %mm% lss 3 set /A mm+=12, yy-=1
set /A a=yy/100, b=a/4, c=2-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10, dow=(c+dd+e+f-1523)%%7
echo Today log data > Day-%dow%.txt

如果这不是您想要的,请指出问题,以便我解决。

编辑:以下版本获取独立于语言环境设置的日期部分:

@echo off
for /F "skip=1 tokens=2-4 delims=(-/)" %%A in ('date ^< NUL') do (
   for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
      set %%A=%%a
      set %%B=%%b
      set %%C=%%c
   )
)
set /A mm=10%mm% %% 100, dd=10%dd% %% 100
if %mm% lss 3 set /A mm+=12, yy-=1
set /A a=yy/100, b=a/4, c=2-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10, 

dow=(c+dd+e+f-1523)%%7
echo Today log data > Day-%dow%.txt

编辑:下面的版本将星期几插入为 3 个字母的短名称:

@echo off
for /F "skip=1 tokens=2-4 delims=(-/)" %%A in ('date ^< NUL') do (
   for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
      set %%A=%%a
      set %%B=%%b
      set %%C=%%c
   )
)
set /A mm=10%mm% %% 100, dd=10%dd% %% 100
if %mm% lss 3 set /A mm+=12, yy-=1
set /A a=yy/100, b=a/4, c=2-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10, 

dow=(c+dd+e+f-1523)%%7 + 1
for /F "tokens=%dow%" %%a in ("Sun Mon Tue Wed Thu Fri Sat") do set dow=%%a
echo Today log data > Day-%dow%.txt

问候,

安东尼奥

于 2012-07-15T16:21:45.107 回答
3

结果比我最初怀疑的要复杂得多,我想这就是让我感兴趣的地方,我搜索了每一个地方,并且给出的所有方法在 Windows 7 上都不起作用。

所以我有一个使用 Visual Basic 脚本的替代解决方案。

批处理创建并执行脚本(DayOfWeek.vbs),将脚本输出(星期一、星期二等)分配给一个变量(dow),然后检查该变量并为另一个变量(dpwnum)分配天数,然后是 VBS已删除希望对您有帮助:

@echo off

REM Create VBS that will get day of week in same directory as batch
echo wscript.echo WeekdayName(Weekday(Date))>>DayOfWeek.vbs

REM Cycle through output to get day of week i.e monday,tuesday etc
for /f "delims=" %%a in ('cscript /nologo DayOfWeek.vbs') do @set dow=%%a

REM delete vbs
del DayOfWeek.vbs

REM Used for testing outputs days name
echo %dow%

REM Case of the days name is important must have a capital letter at start
REM Check days name and assign value depending
IF %dow%==Monday set downum=0
IF %dow%==Tuesday set downum=1
IF %dow%==Wednesday set downum=2
IF %dow%==Thursday set downum=3
IF %dow%==Friday set downum=4
IF %dow%==Saturday set downum=5
IF %dow%==Sunday set downum=6

REM print the days number 0-mon,1-tue ... 6-sun
echo %downum%

REM set a file name using day of week number
set myfile=%downum%.bak

echo %myfile%

pause
exit

编辑:

虽然我转向 VBS,但它可以纯批处理完成,我花了一段时间才让它工作并进行了大量搜索,但这似乎有效:

 @echo off
SETLOCAL enabledelayedexpansion
SET /a count=0
FOR /F "skip=1" %%D IN ('wmic path win32_localtime get dayofweek') DO (
    if "!count!" GTR "0" GOTO next
    set dow=%%D
    SET /a count+=1
)
:next
echo %dow%
pause

对上述批次的唯一警告是,它的星期几是 1-7 而不是 0-6

于 2012-07-20T21:42:23.690 回答
3

这对我有用

FOR /F "tokens=3" %%a in ('robocopy ^|find "Started"') DO SET TODAY=%%a
于 2014-03-06T04:36:56.653 回答
2

我在美国。我可以在 Windows 7、Windows 2008 R2、Windows Server 2003、Windows XP 中运行此代码(所有操作系统都是最新的 Windows 更新和补丁)。所有都具有短日期设置,没有 ddd(或 dddd)(星期几)。

@echo off
for /f %%a in ('date /t') do set DAY=%%a
echo.
echo The Day Is: %DAY%
echo.

如果今天是星期四,它将输出“The Day Is: Thu”。

这将返回我测试过的所有 4 个 Windows 版本的日期。而且只有一天。当我将我的短日期设置更改为“ddd,M/d/yyyy”时,我的输出会用逗号(例如,星期四)显示日期,这告诉我这段代码确实使用短日期格式。但也可能发生的是,如果短日期不包含星期几,它可能会查看我测试的所有 4 台机器上的长日期格式,格式中都有 dddd。

于 2014-02-06T18:32:14.763 回答
2

这不是我的工作(好吧,我从示例中稍微修改了它),而且游戏已经很晚了,但这对我来说适用于 Server 2003;

@echo off  
set daysofweek=Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday  
for /F "skip=2 tokens=2-4 delims=," %%A in ('WMIC Path Win32_LocalTime Get DayOfWeek /Format:csv') do set daynumber=%%A  
for /F "tokens=%daynumber% delims=," %%B in ("%daysofweek%") do set day=%%B

引用:技术支持论坛

于 2015-05-13T16:36:55.450 回答
2

首先 - 复制 CON SETUPDAY.001 SET WORKDAY=​​^Z (非常重要 - 没有 cr/lf)

DATE /T >SETUPDAY.002
COPY SETUPDAY.001+SETUPDAY.002 NEWDAY.BAT >nul
CALL NEWDAY.BAT

SET WEEKDAY=%WORKDAY:~0,3%
SET MDY=%WORKDAY:~4,10%

在脚本中使用 %WEEKDAY%

于 2016-03-08T21:49:03.903 回答
1

依赖于区域设置的版本: 在某些环境中,以下将从日期中提取日期名称:

set dayname=%date:~0,3%

它假定日期名称是%date%. 但是,根据机器设置,子字符串部分 ( ~0,3) 需要更改。

像这样的语句将转储到具有三个字符的日期名称的文件中:

set logfile=%date:~0,3%.log
echo some stuff > %logfile%

独立于语言环境的版本:如果您需要较少依赖当前机器的日期格式,另一种方法是编写一个打印星期几的小型应用程序。然后使用批处理文件中该程序的输出。例如,下面的 C 应用程序打印dayN其中 N=0..6。

#include <stdio.h>
#include <time.h>

int main( int argc, char* argv[] )
{
   time_t curtime;
   struct tm * tmval;

   time( &curtime );
   tmval = localtime( &curtime );
   // print dayN.  Or use a switch statement and print
   // the actual day name if you want
   printf( "day%d", tmval->tm_wday );
}

如果上面的内容被编译并链接为myday.exe,那么您可以从批处理文件中使用它,如下所示:

for /f %%d in ('myday.exe') do set logfile=%%d.log
echo some stuff > %logfile%
于 2012-07-06T14:38:42.813 回答
1

我有这个解决方案适合我:

在 cmd 文件所在的同一目录中创建一个名为 dayOfWeek.vbs 的文件。

dayOfWeek.vbs包含一行:

wscript.stdout.write weekdayname(weekday(date))

或者,如果您想要天数而不是名称:

wscript.stdout.write weekday(date)

cmd 文件将包含以下行:

For /F %%A In ('CScript dayOfWeek.vbs //NoLogo') Do Set dayName=%%A

现在您可以使用变量dayName,例如:

robocopy c:\inetpub \\DCStorage1\Share1\WebServer\InetPub_%dayName% /S /XD history logs
于 2014-07-04T15:54:01.790 回答
1

关于这个话题的另一个旋转。下面的脚本显示当前周围的几天,带有星期几前缀。

核心是独立的 :dpack 例程,它将日期编码为一个值,其模 7 显示符合 ISO 8601 标准的星期几(Mon == 0)。还提供了 :dunpk ,它是反函数:

@echo off& setlocal enabledelayedexpansion
rem 10/23/2018 daydate.bat: Most recent version at paulhoule.com/daydate
rem Example of date manipulation within a .BAT file.
rem This is accomplished by first packing the date into a single number.
rem This demo .bat displays dates surrounding the current date, prefixed
rem with the day-of-week.

set days=0Mon1Tue2Wed3Thu4Fri5Sat6Sun
call :dgetl y m d
call :dpack p %y% %m% %d%
for /l %%o in (-3,1,3) do (
  set /a od=p+%%o
  call :dunpk y m d !od!
  set /a dow=od%%7
  for %%d in (!dow!) do set day=!days:*%%d=!& set day=!day:~,3!
  echo !day! !y! !m! !d!
)
exit /b


rem gets local date returning year month day as separate variables
rem in: %1 %2 %3=var names for returned year month day
:dgetl
setlocal& set "z="
for /f "skip=1" %%a in ('wmic os get localdatetime') do set z=!z!%%a
set /a y=%z:~0,4%, m=1%z:~4,2% %%100, d=1%z:~6,2% %%100
endlocal& set /a %1=%y%, %2=%m%, %3=%d%& exit /b


rem packs date (y,m,d) into count of days since 1/1/1 (0..n)
rem in: %1=return var name, %2= y (1..n), %3=m (1..12), %4=d (1..31)
rem out: set %1= days since 1/1/1 (modulo 7 is weekday, Mon= 0)
:dpack
setlocal enabledelayedexpansion
set mtb=xxx  0 31 59 90120151181212243273304334& set /a r=%3*3
set /a t=%2-(12-%3)/10, r=365*(%2-1)+%4+!mtb:~%r%,3!+t/4-(t/100-t/400)-1
endlocal& set %1=%r%& exit /b


rem inverse of date packer
rem in: %1 %2 %3=var names for returned year month day
rem %4= packed date (large decimal number, eg 736989)
:dunpk
setlocal& set /a y=%4+366, y+=y/146097*3+(y%%146097-60)/36524
set /a y+=y/1461*3+(y%%1461-60)/365, d=y%%366+1, y/=366
set e=31 60 91 121 152 182 213 244 274 305 335
set m=1& for %%x in (%e%) do if %d% gtr %%x set /a m+=1, d=%d%-%%x
endlocal& set /a %1=%y%, %2=%m%, %3=%d%& exit /b
于 2018-10-24T02:47:12.483 回答
0
Rem Remove the end comma and add /A to set for this line worked for me.
set /A a=yy/100, b=a/4, c=2-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10 
于 2013-12-01T21:09:39.850 回答
0

如果您可以将PC中的短日期格式更改为“ddd yyyy-MM-dd”(只有第一个参数“ddd”是强制性的),那么以下命令返回-

c:\>vol | date
The current date is: Mon 2014-12-01

然后你可以写你的批处理文件 -

@echo off

vol | date | find /i "sun" > nul 
if not errorlevel 1 goto SUN

vol | date | find /i "mon" > nul 
if not errorlevel 1 goto MON

      # write block for other week days    

goto END

:SUN
set fname="sun"
goto BACKUP

:MON
set fname="mon"
goto BACKUP

      # write block for other week days

:BACKUP
echo %fname%

:END
于 2014-12-01T05:08:36.640 回答
0

正在寻找自己这样做,并看到有关空白行的投诉:

rem Make the win32_localtime output all one line, though some versions may contain blank lines as well.
rem So ignore blank lines and just pick up the number after the equal sign.
for /f "delims== tokens=2" %%a in ('wmic path win32_localtime get dayofweek /format:list') do (
    rem Increment the DOW as it is documented to be a zero-based index starting with Sunday.
    set /a DayOfWeekIndex=%%a+1
)
rem Also get name day of week. The DOW coming in is now a one-based index.
rem This is used to reference the "array" of week day names.
set DayOfWeekNames=Sun Mon Tue Wed Thu Fri Sat
for /f "tokens=%DayOfWeekIndex%" %%b in ("%DayOfWeekNames%") do (
    set DayOfWeekName=%%b
)
于 2017-01-18T22:52:16.680 回答
0

我改进了 Aacini答案 以使其回显一周中的全天名称

所以这是我的代码

@echo off
for /F "skip=1 tokens=2-4 delims=(-/)" %%A in ('date ^< NUL') do (
   for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
      set %%A=%%a
      set %%B=%%b
      set %%C=%%c
   )
)
set /A mm=10%mm% %% 100, dd=10%dd% %% 100
if %mm% lss 3 set /A mm+=12, yy-=1
set /A a=yy/100, b=a/4, c=4-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10,dow=(c+dd+e+f-1523)%%7 + 1
for /F "tokens=%dow%" %%a in ("Sunday Monday Tuesday Wednesday Thursday Friday Saturday ") do set dow=%%a
echo Today is %dow%>"Today is %dow%.txt"
echo Today is %dow%
Pause>Nul

REM Sun Mon Tue Wed Thu Fri Sat
REM Sunday Monday Tuesday Wednesday Thursday Friday Saturday  
于 2018-02-12T07:21:45.980 回答
-1

使用 MSHTA 和 javascript 的版本。将 %jsfunc% 更改为您要调用的任何 jscript 函数

@echo off
::Invoke a javascript function using mhta

set jsfunc=new Date().getDay()
set dialog="about:<script>resizeTo(0,0);new ActiveXObject('Scripting.FileSystemObject').
set dialog=%dialog%GetStandardStream(1).WriteLine(%jsfunc%);close();</script>"

for /f "tokens=* delims=" %%p in ('mshta.exe %dialog%') do set ndow=%%p

::get dow string from array of strings  
for /f "tokens=%ndow%"  %%d in ("Mon Tue Wed Thu Fri Sat Sun") do set dow=%%d 

echo dow is : %ndow%  %dow%
pause
于 2016-05-09T22:10:05.997 回答