在Windows批处理脚本中格式化日期和时间

247

在Windows(Windows XP)批处理脚本中,我需要格式化当前日期和时间以便稍后用于文件名等。

这与Stack Overflow的问题 如何在批处理文件中追加日期类似,但是还包括时间。

到目前为止,我有:

echo %DATE%
echo %TIME%
set datetimef=%date:~-4%_%date:~3,2%_%date:~0,2%__%time:~0,2%_%time:~3,2%_%time:~6,2%
echo %datetimef%

得到以下结果:

28/07/2009
 8:35:31.01
2009_07_28__ 8_36_01

有没有办法在 %TIME% 中允许单个数字的小时数,这样我就可以得到以下结果?

2009_07_28__08_36_01

无论区域设置如何,在批处理文件中拆分%date% - phuclv
你可以将datetimef变量中的空格替换为0。例如:SET datetimef=%datetimef: =0% - SebaGra
37个回答

172
我最终得到了这个脚本:
set hour=%time:~0,2%
if "%hour:~0,1%" == " " set hour=0%hour:~1,1%
echo hour=%hour%
set min=%time:~3,2%
if "%min:~0,1%" == " " set min=0%min:~1,1%
echo min=%min%
set secs=%time:~6,2%
if "%secs:~0,1%" == " " set secs=0%secs:~1,1%
echo secs=%secs%

set year=%date:~-4%
echo year=%year%

:: 在 WIN2008R2 上,例如我需要将你的 'set month=%date:~3,2%' 修改为以下形式 ::否则月份为 00

set month=%date:~4,2%
if "%month:~0,1%" == " " set month=0%month:~1,1%
echo month=%month%
set day=%date:~0,2%
if "%day:~0,1%" == " " set day=0%day:~1,1%
echo day=%day%

set datetimef=%year%%month%%day%_%hour%%min%%secs%

echo datetimef=%datetimef%

11
在 Windows Server 2003 和 Windows 7 上,这个脚本给出了 "201200Mo_085806"(正确的年份和时间)。 - sfuqua
57
针对那些通过谷歌等搜索引擎来到这里的人,需要注意:此操作受地区影响,因此在非英语Windows系统上可能需要进行微调才能正常运行! - PiotrK
我是这样做的: Time /T > Time.dat set /P ftime= < Time.dat set fDate=%date:6%%date:3,2%%date:0,2%%ftime:0,2%%ftime:~3,2% echo %fDate%-> 201310170928 - Ice
7
只需要使用普通的字符串替换,就可以在只有两行代码的情况下完成所有操作:https://dev59.com/bXM_5IYBdhLWcg3w3nRs#23558738 - Andreas
1
请注意,当您将日期拉回时,日期是错误的。应该使用%date:7,2%来获取日期。如果您使用%date:0,2%,它会返回星期几,而不是月份中的日期。 - user1853517
显示剩余2条评论

100

每当我需要一个日期/时间字符串时,我通常会这样做:

set dt=%DATE:~6,4%_%DATE:~3,2%_%DATE:~0,2%__%TIME:~0,2%_%TIME:~3,2%_%TIME:~6,2%
set dt=%dt: =0%

这是德国日期/时间格式 (dd.mm.yyyy hh:mm:ss)。基本上我将子字符串连接起来,最后用零替换所有的空格。

得到的字符串的格式为: yyyy_mm_dd__hh_mm_ss


关于子字符串的简短说明:

%VARIABLE:~num_chars_to_skip,num_chars_to_keep%

要从日期“29.03.2018”中获取年份,使用以下代码:

%DATE:~6,4%
       ^-----skip 6 characters
         ^---keep 4 characters 

11
当你只需要干净的时间戳(没有空格或其他字符)时,迄今为止最优雅的解决方案。 - jvdneste
2
最佳答案是因为它解释了如何打印变量,而不是强制使用一些对很多人来说可能不同的子字符串。我总是先运行echo %date%_%time%,看看变量单独打印出什么,然后决定我想要保留哪些子字符串。 - Tomislav3008
你如何获取UTC时区呢?例如,在结果字符串末尾添加“+01”? - Andreas L.
@AndreasL。在命令行上获取时区信息需要使用其他工具。例如,您可以使用systeminfo,像这样:for /F "tokens=2 delims=^(: " %i in ('systeminfo^|find "Zeit"') do set "tz=%i"(假设您正在使用德语Windows)。请注意,如果要在批处理文件中使用此命令,需要将%加倍。 - Andreas

81

以下是我生成日志文件名的方法(基于http://ss64.com/nt/syntax-getdate.html):

@ECHO OFF
:: Check WMIC is available
WMIC.EXE Alias /? >NUL 2>&1 || GOTO s_error

:: Use WMIC to retrieve date and time
FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
   IF "%%~L"=="" goto s_done
      Set _yyyy=%%L
      Set _mm=00%%J
      Set _dd=00%%G
      Set _hour=00%%H
      SET _minute=00%%I
      SET _second=00%%K
)
:s_done

:: Pad digits with leading zeros
      Set _mm=%_mm:~-2%
      Set _dd=%_dd:~-2%
      Set _hour=%_hour:~-2%
      Set _minute=%_minute:~-2%
      Set _second=%_second:~-2%

Set logtimestamp=%_yyyy%-%_mm%-%_dd%_%_hour%_%_minute%_%_second%
goto make_dump

:s_error
echo WMIC is not available, using default log filename
Set logtimestamp=_

:make_dump
set FILENAME=database_dump_%logtimestamp%.sql
...

5
关于在批处理中生成与语言环境无关的时间戳的问题,SO上最佳答案。 - Mike Campbell
2
太棒了!应该有一种方法将其标记为解决方案。 - Rado
这是最佳答案。适用于Windows 7和10西班牙语版本。 - acgbox
有没有办法同时获取毫秒?我需要它们。 - Jon Grah

75
@ECHO OFF
: Sets the proper date and time stamp with 24Hr Time for log file naming
: convention ('YYYYMMDD_HHMMSS')

: Scrapes the characters out of their expected permissions in the date/time
: environment variables.

: Expects a date format of '____MM_DD_YYYY'
: Expects a time format of 'HH:MM:SS' or ' H:MM:SS'

SET HOUR=%time:~0,2%
SET dtStamp9=%date:~-4%%date:~4,2%%date:~7,2%_0%time:~1,1%%time:~3,2%%time:~6,2% 
SET dtStamp24=%date:~-4%%date:~4,2%%date:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%

if "%HOUR:~0,1%" == " " (SET dtStamp=%dtStamp9%) else (SET dtStamp=%dtStamp24%)

ECHO %dtStamp%

PAUSE

2
在Windows Server 2003和Windows 7上,这给了我正确的字符串。比我过去构建的更优雅,所以谢谢你! - sfuqua
3
这是在 Windows 7 上使用俄语区域设置时的输出结果。当前时间为2013-05-03T02:22:51,但脚本打印出的是“2013-5.-01_02_22_51”。 - nightcoder
8
日期格式(%date%)在不同语言环境下会有不同的字符串表示。 - AechoLiu
2
以捷克语环境返回20146.0._173502给我。 - Muflix
2
win7 64位旗舰版,时间错误:20140.01_131612,应为(2014.10.26_131612) - jmp

53
如果已安装PowerShell,则可以轻松可靠地以任何格式获取所需的日期/时间,例如:
for /f %%a in ('powershell -Command "Get-Date -format yyyy_MM_dd__HH_mm_ss"') do set datetime=%%a
move "%oldfile%" "backup-%datetime%"

当然,现在PowerShell通常已经安装了,但如果你正在使用Windows XP,则只有在已知PowerShell可用的环境中才需要使用此技术(或在批处理文件中检查PowerShell是否可用...)

你可能会合理地问:如果您可以使用PowerShell获取日期/时间,为什么还要使用批处理文件,但我认为一些明显的原因是:(a) 您对PowerShell并不是很熟悉,仍然更喜欢使用旧式的批处理文件完成大部分操作,或者(b) 您正在更新旧脚本,不想将整个脚本转换为PowerShell。


这个解决方案的问题在于,当您想要在格式中添加空格时会出现问题 - 例如 HH:mm tt - JGFMK
@JGFMK:"delims=" 可以解决这个问题。 - Stephan

36

我今天遇到了这个问题,并用以下方法解决了它:

SET LOGTIME=%TIME: =0%

它用0替换空格,并将小时数前导零填充。

经过一些快速搜索,我没有发现它是否需要命令扩展(仍然可以使用SETLOCAL DISABLEEXTENSIONS)。


好的,变量替换。现在 - 如何替换冒号(:)? - Tomasz Gandor
@TomaszGandor 这对我有效:echo %TIME: =:%,但如果不行的话,可以尝试用 ^ 转义 :,像这样 echo %TIME: =^:%(这对我也有效)。 - opello
1
+1 简洁明了。文件名中不允许使用冒号。set theTime=%Time::=% 可以删除它们。你能否在一条语句中将空格替换为0,删除冒号并截取6个字符(从而删除小数部分)?如果需要两三行也没关系,我只是好奇。 - riderBill
不是我知道的。如果你找到了,请跟进! - opello

20

正如已经指出的,只有在您知道当前用户使用的格式(例如,MM / dd / yy或dd-MM-yyyy仅仅是举例)时,解析日期和时间才有用。这可以确定,但是当您进行所有的强调和解析时,仍然会出现使用非预期格式的情况,并且需要进行更多的调整。

您还可以使用某些外部程序,在您喜欢的格式中返回日期标记,但这会导致需要将实用程序与脚本/批处理一起分发的缺点。

还有一些使用CMOS时钟的批处理技巧,但对于大多数人来说,这太接近裸线了,而且也不总是检索日期/时间的首选位置。

以下是避免上述问题的解决方案。是的,它引入了其他问题,但对于我的目的,我发现这是为现代Windows系统中的.bat文件创建日期时间戳的最简单、最清晰、最可移植的解决方案。这只是一个示例,但我认为您将看到如何修改其他日期和/或时间格式等。

reg copy "HKCU\Control Panel\International" "HKCU\Control Panel\International-Temp" /f
reg add "HKCU\Control Panel\International" /v sShortDate /d "yyMMdd" /f
@REM reg query "HKCU\Control Panel\International" /v sShortDate
set LogDate=%date%
reg copy "HKCU\Control Panel\International-Temp" "HKCU\Control Panel\International" /f

13
这是一个糟糕的解决方案。如果失败了,那么全局设置将永久改变。它还会与其他应用程序引入竞争条件。 - MikeKulls
你可以使用reg query "HKCU\Control Panel\International" /v sShortDate部分而不更改注册表设置(留给读者练习!)。 - tricasse

14

如果您不是非常需要这种格式:

2009_07_28__08_36_01

您可以使用以下三行代码,其中使用了%date%和%time%:

set mydate=%date:/=%
set mytime=%time::=%
set mytimestamp=%mydate: =_%_%mytime:.=_%
注意:字符/:被移除,字符.和空格则被替换为下划线。
例如输出结果(于2015年8月5日星期三下午12:49:50.093捕获):
echo %mytimestamp%
Wed_08052015_124950_93

1
当小时数小于12时,设置mydate为%date:/=%。 设置mytime为%time::=%,然后将mytime中的空格替换为0。 设置mytimestamp为%mydate: =%%mytime:.=_%。 - ragche

9
REM Assumes UK style date format for date environment variable (DD/MM/YYYY).
REM Assumes times before 10:00:00 (10am) displayed padded with a space instead of a zero.
REM If first character of time is a space (less than 1) then set DATETIME to:
REM YYYY-MM-DD-0h-mm-ss
REM Otherwise, set DATETIME to:
REM YYYY-MM-DD-HH-mm-ss
REM Year, month, day format provides better filename sorting (otherwise, days grouped
REM together when sorted alphabetically).

IF "%time:~0,1%" LSS "1" (
   SET DATETIME=%date:~6,4%-%date:~3,2%-%date:~0,2%-0%time:~1,1%-%time:~3,2%-%time:~6,2%
) ELSE (
   SET DATETIME=%date:~6,4%-%date:~3,2%-%date:~0,2%-%time:~0,2%-%time:~3,2%-%time:~6,2%
)

ECHO %DATETIME%

只是想说我来自英国,但在某个时候我更改了日期格式为yyyy-mm-dd,所以这对我不起作用。 - mwfearnley

9
以下内容可能不是直接答案,但是相似的意思吗?
set hour=%time:~0,2%
if "%hour:~0,1%" == " " set datetimef=%date:~-4%_%date:~3,2%_%date:~0,2%__0%time:~1,2%_%time:~3,2%_%time:~6,2%
else set datetimef=%date:~-4%_%date:~3,2%_%date:~0,2%__%time:~0,2%_%time:~3,2%_%time:~6,2%

至少这可能会激发灵感。


使用%date%/%time%的答案非常依赖于本地设置。这个期望的格式是什么? - mwfearnley

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