从Server 2016中的计划任务运行时,%date%在批处理文件中生成不同的结果

时间:2017-06-20 23:49:01

标签: windows batch-file

批处理文件正在运行robocopy并创建robocopyServer_%date%.txt的日志文件

手动运行批处理文件时,结果为robocopyServer_yyyy-mm-dd.txt

当批处理文件从计划任务运行时,结果是robocopyServer_Tue(或一周中的任何一天) - 并且没有文件扩展名。

此批处理文件在Server 2012R2(手动或计划任务)下运行良好。

4 个答案:

答案 0 :(得分:5)

%date%或date /t始终不可靠,因为它取决于地区和用户设置。以下是如何获得普遍有效的日期:

for /f %%# in ('wmic os get localdatetime^|findstr .') do if "%%#" neq "" set date=%%#
set date=%date:~,4%-%date:~4,2%-%date:~6,2%
echo %date%

这将以yyyy-mm-dd格式回显当前日期。

答案 1 :(得分:1)

环境变量字符串 DATE TIME 的格式取决于为已使用帐户定义的Windows区域设置。

可以使用Windows Management Instrumentation Command行工具 WMIC 获取与地区无关的日期/时间字符串。

使用命令行

wmic OS GET LocalDateTime /VALUE

输出UTF-16 Little Endian编码,例如:

 
 
LocalDateTime=20170621095402.953000+120
 
 

有两个空行,然后是当前语言环境日期/时间的行,格式为YYYYMMDDHHmmSS.microsecond±UTC偏移量,单位为分钟,另外两行为空行。

这些数据可以与批处理代码一起使用,如下所示:

@echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "FileNameDate=%%I"
set "FileNameDate=%FileNameDate:~0,4%-%FileNameDate:~4,2%-%FileNameDate:~6,2%"
echo %FileNameDate%

对文件和文件夹名称感兴趣的只是等号和小数点之间的日期/时间字符串,这是使用for /F选项tokens=2 delims==.获取20170621095402的原因分配给循环变量I,其值在环境变量FileNameDate旁边分配。

使用字符串替换重新格式化环境变量FileNameDate以获取格式为YYYY-MM-DD的日期字符串,输出以进行2017-06-21的验证。

使用 WMIC 获取本地日期/时间的优势在于Windows区域设置是独立的。缺点是与使用 DATE TIME 环境变量(在几微秒内访问)相比,命令执行需要相当长的时间(1到2秒)。

命令 FOR 在解析Unicode输出正确方面存在问题。它解释 WMIC 输出结束时的字节序列0D 00 0A 00 0D 00 0A 00,因为两个空行为0D 0D 0A,即两个回车和一个换行。这会导致将 WMIC 输出末尾的最后两个空行解释为单行,并将单个回车符作为字符串。

这通常是一个问题,因为set "EnvironmentVariable=%%I"的结果是%%I在使用正确的值删除之前已定义的环境变量时将& goto Label扩展为回车。

有多种解决方案可以解决命令 FOR 的Unicode解析错误。一旦将值分配给环境变量,就可以附加:Label以退出循环,跳转到 FOR 循环下面的/VALUE,以避免遇到此问题所有

另一个解决方案是此代码中使用的解决方案。由于使用 WMIC 选项tokens=2,属性的名称及其值将在同一行上输出。命令 FOR 运行命令 SET ,因为delims==.仅当它可以使用等号和点将当前行拆分为至少2个子串(标记)时作为echo /?的分隔符。但 WMIC 输出的错误解析结束是 FOR 一行只包含回车符,因此没有第二个令牌。出于这个原因,错误解析的空行在这里也被 FOR 忽略。

有关解析UTF-16 LE编码输出上 FOR 问题的详细信息,请参阅How to correct variable overwriting misbehavior when parsing output?cmd is somehow writing Chinese text as output

要了解使用的命令及其工作原理,请打开命令提示符窗口,执行以下命令,并完全阅读为每个命令显示的所有帮助页面。

  • for /?
  • set /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?
  • false

答案 2 :(得分:1)

您必须为用于运行任务的用户创建Windows配置文件,并在该配置文件下配置区域设置和日期格式。

答案 3 :(得分:0)

我有一个与OP类似的问题,我喜欢使用wmic @Regejok的方法。这是我处理DOS DATE返回的唯一字符串的解决方案(美国解决方案-很抱歉,没有其他要测试的区域操作系统,但是可以在其他区域快速重构)。

我的服务器在%DATE%(日期/ t)返回了不同的字符串。

例如。 1-2018年7月4日星期三(完全正确的字符串)

例如。 2-07/04/2018 (另一个非常好的字符串,但由于子字符串引用而使我的批处理脚本失败)

我使用此脚本从DATE&TIME中选择子字符串来创建用于记录和归档文件的日期/时间戳变量:

原始脚本

@echo off
set HH=%TIME:~0,1%
if "%HH%"==" " goto addzero
goto hourOK
:addzero
set HH=0%TIME:~1,1%
goto end
:hourOK
set HH=%TIME:~0,2%
:end

set mn=%TIME:~3,2%
set SS=%TIME:~6,2%
set ms=%TIME:~9,2%
set MM=%DATE:~4,2%
set DD=%DATE:~7,2%
set YY=%DATE:~-2%
set CCYY=%DATE:~-4%
set dts=%CCYY%%MM%%DD%%HH%%mn%%SS%%ms%
set dateonly=%CCYY%%MM%%DD%
set monthlog=%CCYY%%MM%
@echo on

请不要判断代码。 :)会变得更好。

“ 2018年7月4日星期三”的结果:

C:\>set HH=
C:\>if " " == " " goto addzero
C:\>set HH=09
C:\>goto end
C:\>set mn=30
C:\>set SS=49
C:\>set ms=69
C:\>set MM=07
C:\>set DD=04
C:\>set YY=18
C:\>set CCYY=2018
C:\>set dts=2018070409304969
C:\>set dateonly=20180704
C:\>set monthlog=201807

这与前任非常有效。 1个字符串。我跳过了缩写的日期(星期三),一切都很好。直到我遇到了一个返回ex的服务器。 2。

'07 / 04/2018'的失败结果:

C:\>set HH=
C:\>if " " == " " goto addzero
C:\>set HH=09
C:\>goto end
C:\>set mn=31
C:\>set SS=48
C:\>set ms=59
C:\>set MM=4/
C:\>set DD=01
C:\>set YY=18
C:\>set CCYY=2018
C:\>set dts=20184/0109314859
C:\>set dateonly=20184/01
C:\>set monthlog=20184/

所有日期/时间戳均包含“ /”(文件命名失败)。这都是由于DATE字符串差异和子字符串引用引起的。时间很好。 即使在月份(MM)和日期(DD)字符串中出现故障,我也注意到2位数和4位数的Year vars很好(YY&CCYY)。怎么样?负引用。 这成为我最终脚本的最大修复方法。以及字符串替换。

我的新脚本 (我仍然喜欢使用wmic的方法,这是另一种允许仅使用DOS的DATE返回2种不同返回类型的方法)

01  @echo off
02  set str=%DATE%      
03  set str=%str:/=%     
04 
05  set MM=%str:~-8,2%  
06  set DD=%str:~-6,2%  
07  set YY=%str:~-2%    
08  set CCYY=%str:~-4%  
09
10  set HH=%TIME:~0,2%  
11  set HH=%HH: =0%     
12  set mn=%TIME:~3,2%  
13  set SS=%TIME:~6,2%  
14  set ms=%TIME:~9,2%  
15
16  set _dts=%CCYY%%MM%%DD%%HH%%mn%%SS%%ms%
17  set _dateonly=%CCYY%%MM%%DD%
18  set _monthlog=%CCYY%%MM%
19  @echo on

注释:

第2行:

'str' var holds the value returned from DATE. 
Could be formatted like ex. 1 or ex. 2, does not matter

第3行:

this is string replacement, all '/' replaced with '' (null). 
ex. 1 - 'Wed 07/04/2018' >> 'Wed 07042018', ex. 2 - '07/04/2018' >> '07042018'

第5行:

this is where negative referencing made both date strings equal (in a sense), 
month (MM) starts at '-8' characters from the end of the string in both 
examples, length of '2'

第6行:

Same with day (DD), '-6' characters from end of string, length of '2'

第7行:

2-digit year (YY) works as it did before (already used negative referencing)

第8行:

4-digit year (CCYY) works as it did before as well

第10行:

TIME always returns 2-digits in its hour (HH) position, it just doesn't have
a leading '0' if less than 10, what it does return is a leading space 
i.e. %TIME:~0,2% will return ' 9' for 9:00 AM (not desired for date/timestamps)

第11行:

string replacement to the rescue again, replace all spaces with '0', 
turns the ' 9' to '09' (exactly what we want)

第12行:

minutes, seconds, milliseconds all work as they did previously, using 
sub-strings to avoid the colons (':') & the period ('.') in the time stamp 
i.e. 10:01:26.29

新脚本的结果:

C:\>set str=07/04/2018
C:\>set str=07042018
C:\>set MM=07
C:\>set DD=04
C:\>set YY=18
C:\>set CCYY=2018
C:\>set HH= 9
C:\>set HH=09
C:\>set mn=42
C:\>set SS=26
C:\>set ms=48
C:\>set _dts=2018070409422648
C:\>set _dateonly=20180704
C:\>set _monthlog=201807


C:\>set str=Wed 07/04/2018
C:\>set str=Wed 07042018
C:\>set MM=07
C:\>set DD=04
C:\>set YY=18
C:\>set CCYY=2018
C:\>set HH=10
C:\>set HH=10
C:\>set mn=50
C:\>set SS=55
C:\>set ms=48
C:\>set dts=2018070410505548
C:\>set dateonly=20180704
C:\>set monthlog=201807

希望这会有所帮助。这不是唯一的,也不是地球崩溃,只是另一种方式。