批处理命令中文件名包含日期和时间

81

我正在使用命令行上的WinZip来压缩文件。由于我们每天都要进行归档,因此我尝试在这些文件中添加日期和时间,以便每次自动生成一个新文件。

我使用以下内容生成文件名。将其复制粘贴到您的命令行中,您应该会看到带有日期和时间组件的文件名。

echo Archive_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.zip

输出

Archive_20111011_ 93609.zip

然而,我的问题是关于上午下午的。AM时间戳给了我带前导空格的时间9,而不是像自然情况下占据两个空格的10

我猜我的问题也将扩展到前九天、前九个月等等。

我该如何修复这个问题,以便包括前导零而不是前导空格,以便得到Archive_20111011_093609.zip


4
我最终使用了你的方法进行日常任务,所有答案都更加混乱。 - rrrhys
15个回答

86

另一个解决方案:

for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set datetime=%%I

它将为您提供(与地区设置无关!):

  20130802203023.304000+120
( YYYYMMDDhhmmss.<milliseconds><always 000>+/-<minutes difference to UTC>  )

从这里开始,很容易:

set datetime=%datetime:~0,8%-%datetime:~8,6%
20130802-203023

针对Logan的请求,要求文件的“日期时间修改”采用相同的输出格式:

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%

这有点复杂,因为它只能使用完整路径,wmic希望反斜杠被加倍并且=必须被转义(第一个需要转义,第二个则由引号括起来保护)。


1
太棒了!(wmic命令的示例输出:LocalDateTime=20140619212037.828000+120 - Peter Mortensen
3
%%I是用于批处理文件中的语法。如果您在命令提示符上直接使用该行,则必须使用%I代替。 - Stephan
wmic os get localdatetime | findstr /r "^20" - yzorg
这个与语言环境无关的解决方案非常适合我的脚本,因为它必须在FIGS、日语和韩语中运行! - Matthew
1
@Jonathan:这取决于您的需求。您的解决方案提供了没有前导零的值-当您想对结果进行数学运算时,这非常好,但会使构建日期时间字符串变得复杂。2020113是什么?一月的第13天还是三月的第11天? - Stephan
显示剩余5条评论

61
提取小时数,查找是否有前导空格,如果有,则用零替换。
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

12
为什么需要搜索,你可以直接用零替换所有空格“set hr=%hr: =0%”。 - jeb
3
@jeb,为什么评论而不是回答?(意为:为什么你只发表了评论而没有给出答案?) - JoelFan
我得到了 Archive_b-%a%cc-_142053.zip - RomanKousta
3
@ZinanXing说:因为这个解决方案依赖于本地设置(不同国家时间日期格式的差异)。这就是我更喜欢wmic解决方案的原因(请看我对这个问题的回答)。 - Stephan

24

你可以搜索一下,简单地将所有空格替换为零:set hr=%hr: =0% - jeb Oct 11 '11 at 14:16

于是我这样做了:

set hr=%time:~0,2%
set hr=%hr: =0%

然后在您正在格式化的任何字符串中使用%hr%,以始终获取两位数的小时。

(Jeb在最受欢迎的答案下发表的评论对我来说效果最好,也是最简单的。我在此重新发布它,以便将来的用户更容易找到。)


3
很遗憾你不能链式转换。 %time:~0,2: =0% 本来是挺好的 :^( - Michael
这对我来说似乎是最佳解决方案...向发送WMIC信息的人表示祝贺...尤其是独立日期格式"wmic os get localdatetime",对我非常有用..再次感谢大家...保持良好状态... - ZEE
哇,真的很酷而且简短的解决方案。我不知道你可以像这样替换环境变量中的数字:D - Radon8472

17

在阅读了你们所有的答案后,我找到了最适合我的解决方案:

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%"

如果是上午,将得到带有前导空格和时间的20160915_150101

如果是下午,则会得到20160915_2150101


如果你添加 set d=%d: =0%,它会用零替换那个空格。 - CrazyPenguin
1
感谢CrazyPenguinset t=%date%%time% set d=%t:10,4%%t:7,2%%t:~4,2%%t:15,2%%t:18,2%%t:~21,2% set d=%d: =0% echo hello>"Archive_%d%" - Nesar
1
如果有人想知道 "set d=%d: =0%" 将放在哪里,它将放在第2行和第3行之间。 - Nesar

17

正如Vicky已经指出的那样,%DATE%%TIME%会返回当前日期和时间,使用完全(无限制)可定制的短日期和时间格式。

一个用户可能配置其系统返回Fri040811 08.03PM,而另一个用户可能选择08/04/2011 20:30。

这对于BAT程序员来说是一个完全的噩梦。

将格式更改为固定格式可能会解决问题,前提是在离开BAT文件之前恢复以前的格式。但它可能会受到令人讨厌的竞争条件的影响,并且会使取消的BAT文件恢复变得复杂。

幸运的是,还有一种替代方案。

您可以使用WMIC。 WMIC Path Win32_LocalTime Get Day,Hour,Minute,Month,Second,Year /Format:table 以不变的方式返回日期和时间。非常方便直接用FOR / F命令解析。

因此,将这些部分组合在一起,将其作为起点尝试一下...

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
 )

5
@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"

这个程序会将MB5L.txt文件压缩成ziptest20120204.zip,如果在2012年2月4日运行。


4

在批处理中,您可以像这样向变量(值最高为99)添加前导零:

IF 1%Var% LSS 100 SET Var=0%Var%

因此,您需要将日期和时间组件解析到单独的变量中,对它们进行相同的处理,然后将它们连接在一起以创建文件名。

但是,您解析日期和时间的底层方法取决于系统区域设置。如果您希望您的代码不依赖于特定机器,那么这可能没问题。但如果您希望它能在不同的国际环境下运行,您需要另一种方法,例如读取注册表设置:

HKEY_CURRENT_USER\Control Panel\International\iDate
HKEY_CURRENT_USER\Control Panel\International\iTime
HKEY_CURRENT_USER\Control Panel\International\iTLZero

(据我所知),最后一个控制是否在时间前加上前导零,但不控制日期。

我想再为您的本地设置点赞。我正在我的公司服务器上进行操作,更改语言环境在这些服务器上不是一个选项,所以我相当安全。日期+时间仅仅是任务运行的指示。 - Raj More

2

根据上面的答案,我已经准备好了一个可直接使用的函数。

已使用法语本地设置进行验证。

:::::::: 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

1
正如其他人已经指出的那样,%DATE%%TIME%(以及date /Ttime /T)的日期和时间格式依赖于语言环境,因此提取当前日期和时间总是一场噩梦,并且几乎没有格式限制,因此不可能找到适用于所有可能格式的解决方案。请注意保留HTML标签。

但是像以下代码一样还存在另一个问题(假设日期格式为MM/DD/YYYY,12小时时间格式为h:mm:ss.ff ap,其中apAMPMff为小数秒):

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%

每个%DATE%%TIME%的实例返回其扩展时存在的日期或时间值,因此第一个%DATE%%TIME%表达式可能与后续表达式返回不同的值(当您回显包含大量此类表达式的长字符串时,最好使用%TIME%来验证)。
您可以像这样改进上述代码以仅保留单个%DATE%%TIME%实例:
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%

但是,当在午夜执行时,%DATE%%TIME%返回的值可能反映不同的日期。
要使%CURRDATE%%CURRTIME%具有相同的日期,唯一的方法是:
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%

当然,所描述的问题发生的可能性非常小,但在某个时刻它会发生并导致奇怪的无法解释的故障。


所述问题不会出现在基于wmic命令的方法中,如Stephan用户的答案PA.用户的答案中所述,因此我强烈建议选择其中之一。 wmic的唯一缺点是速度较慢。

0

我意识到这对于“楼主”来说是一个无聊的问题,但我刚刚想出了这个方法,对自己感到有些自豪。

http://gnuwin32.sourceforge.net/packages/gawk.htm 下载Windows版的gawk...然后它就成为了一个简单的一行命令,没有那些笨重的DOS批处理语法,也不需要使用六个FOR循环来分割字符串(真的是很垃圾!当然这只是我的看法)

如果你已经掌握了C、C ++、Perl或Ruby,那么学习AWK(继承自前两者,并对后两者做出了重大贡献)简直易如反掌!!!

DOS批处理命令:

echo %DATE% %TIME% && echo %DATE% %TIME% | gawk -F"[ /:.]" "{printf(""""%s%02d%02d-%02d%02d%02d\n"""", $4, $3, $2, $5, $6, $7);}"

输出:

Tue 04/09/2012 10:40:38.25
20120904-104038

现在这还不是完整的故事...我只是会偷懒,直接在printf语句中硬编码我的日志文件名的剩余部分,因为这样很简单...但如果有人知道如何将%NOW%变量设置为AWK输出的内容(产生“通用”当前时间函数的核心),那我全听着呢。

编辑:

在 Stack Overflow 上进行了快速搜索,找到了这个谜题的最后一块拼图,Bash backticks 的批处理等效项

因此,这三行 DOS 批处理代码:

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%

生成:

20120904-114434

现在我可以在由我的SQL Server安装(2005+)脚本生成的日志文件名称中包含日期时间:

sqlcmd -S .\SQLEXPRESS -d MyDb -e -i MyTSqlCommands.sql >MyTSqlCommands.sql.%now%.log

现在我又是一个快乐的露营者了(除了在Unix上,生活还是要容易得多)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接