Windows批处理:将格式化日期存入变量

126

如何在Windows .bat文件中将当前日期以YYYY-MM-DD格式保存到某个变量中?

Unix shell类比:

today=`date +%F`
echo $today

1
可能是重复问题:Windows批处理脚本格式化日期和时间 - adarshr
1
http://www.robvanderwoude.com/datetime.php - Bali C
1
adarshr,那个问题的答案使用了一种相当可怕且容易出错的处理方式。我建议不要使用它。 - Joey
这个链接有助于理解下面的答案。http://ss64.com/nt/for_f.html - smwikipedia
1
无论区域设置如何,在批处理文件中拆分%date% - phuclv
17个回答

183

您可以使用以下方式以与语言环境无关的方式获取当前日期:

for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined MyDate set MyDate=%%x

然后你可以使用子字符串提取各个部分:

set today=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%

另一种方式是获取包含各个部分的变量:

for /f %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set %%x
set today=%Year%-%Month%-%Day%

这比纠结于子字符串要好得多,但代价是污染变量名称空间。

如果你需要的是UTC时间而不是本地时间,命令基本相同:

for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
set today=%Year%-%Month%-%Day%

1
@user2023861 看起来即使我打开命令提示符,我总是在调用命令时得到正确的日期/时间,而不是我打开命令提示符时的日期/时间。 - ADTC
5
请注意,如果您多次运行上述代码,则不会为每个调用获取新的日期,因为它检查变量是否未定义。这是必要的,因为 for /f 返回两行,后者为空行。您可以通过在两次调用之间使用 set MyDate= 来解决这个问题。我想这就是用户2023861遇到的问题。 - Joey
1
@CharlesWood,虽然如今我通常使用PowerShell,但我仍然努力使自己的批处理文件更加健壮。 - Joey
4
获取日期字符串中两位数字的月份和日期,并且左侧补零,可以使用以下更改后的代码:for /f "tokens=2 delims==." %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set "%%x" set /a Month+=100, Day+=100 set today=%Year%-%Month:~-2%-%Day:~-2%这将在月份和日期前面添加一个额外的100,然后从结果的末尾选取倒数第二和倒数第一位,这样就可以得到两位数字的月份和日期,并且左侧补零。 - Andrus
2
嗨,它可以工作,谢谢。有一个小问题。如何获得两位数的月份? - user3761555
显示剩余10条评论

48

使用date /T命令在命令提示符中查找格式。

如果日期格式为Thu 17/03/2016,请按以下方式使用:

set datestr=%date:~10,4%-%date:~7,2%-%date:~4,2%
echo %datestr%

4
这是最接近所问问题的答案。我只需要一个简单的一句话,而不是一个程序。 - DCookie
6
同意。这里的一些答案看起来几乎像是“安装MS SQL Server,使用SQL客户端连接,然后执行命令SELECT CONVERT(VARCHAR(16), GETDATE(), 112)”。 - isapir
3
ISO-8601格式的日期时间为 %date:~10,4%%date:~7,2%%date:~4,2%T%time:~0,2%%time:~3,2%%time:~6,2% - isapir
10
其他回答看起来像程序的原因是因为,尽管简单,但如果您的Windows区域设置未按照此代码期望的方式配置,则此答案将失败(也就是说,此代码不会在每个Windows系统上都有效)。 - Daniel Scott

43
如果您希望使用标准的MS-DOS命令在批处理文件中实现此操作,则可以使用以下命令:
FOR /F "TOKENS=1 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET dd=%%A
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2,3 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET yyyy=%%C

我相信这可以进一步改进,但它将日期分为三个变量:日(dd),月(mm)和年(yyyy)。您随后可以根据需要在批处理脚本中使用它们。

SET todaysdate=%yyyy%%mm%%dd%
echo %dd%
echo %mm%
echo %yyyy%
echo %todaysdate%

虽然我知道这个问题已经有了一个被接受的答案,但很多人可能会喜欢这种替代方法,以实现不使用WMI控制台的目标,所以我希望它能为这个问题增加一些价值。


4
我发现我需要在Windows 7电脑上稍微修改一下。 需要将标记(tokens)增加一个: ... FOR /F "TOKENS=2,3,4 eol=/ DELIMS=/ " ... - Joe Johnston
1
在Azure上的Win Server 2012上相同。 - Kirill Yunussov
抱歉,此答案仅适用于某些特定的日期格式(甚至不确定是哪种格式),这就是为什么上面的评论说它不起作用。页面上更高的答案无论日期格式如何都有效。 - iisystems

23

以下是两种不依赖于时间设置的方法(均来自于如何获取与本地化无关的日期/时间)。这两种方法都可以获取星期几,且均不需要管理员权限!:

  1. MAKECAB - will work on EVERY Windows system (fast, but creates a small temporary file) (the foxidrive script):

    @echo off
    pushd "%temp%"
    makecab /D RptFileName=~.rpt /D InfFileName=~.inf /f nul >nul
    for /f "tokens=3-7" %%a in ('find /i "makecab"^<~.rpt') do (
        set "current-date=%%e-%%b-%%c"
        set "current-time=%%d"
        set "weekday=%%a"
    )
    del ~.*
    popd
    echo %weekday% %current-date% %current-time%
    pause
    
  2. ROBOCOPY - it's not a native command for Windows XP and Windows Server 2003, but it can be downloaded from the Microsoft site. But it is built-in in everything from Windows Vista and above:

    @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%
    echo Day of the month : %day%
    echo Month : %month%
    echo hour : %HH%
    echo minutes : %MM%
    echo seconds : %SS%
    echo year : %year%
    endlocal
    

    And three more ways that uses other Windows script languages. They will give you more flexibility e.g. you can get week of the year, time in milliseconds and so on.

  3. JScript/BATCH hybrid (need to be saved as .bat). JScript is available on every system from Windows NT and above, as a part of Windows Script Host (though can be disabled through the registry it's a rare case):

    @if (@X)==(@Y) @end /* ---Harmless hybrid line that begins a JScript comment
    
    @echo off
    cscript //E:JScript //nologo "%~f0"
    exit /b 0
    *------------------------------------------------------------------------------*/
    
    function GetCurrentDate() {
        // Today date time which will used to set as default date.
        var todayDate = new Date();
        todayDate = todayDate.getFullYear() + "-" +
                       ("0" + (todayDate.getMonth() + 1)).slice(-2) + "-" +
                       ("0" + todayDate.getDate()).slice(-2) + " " + ("0" + todayDate.getHours()).slice(-2) + ":" +
                       ("0" + todayDate.getMinutes()).slice(-2);
    
        return todayDate;
    }
    
    WScript.Echo(GetCurrentDate());
    
  4. VBScript/BATCH hybrid (Is it possible to embed and execute VBScript within a batch file without using a temporary file?) same case as jscript , but hybridization is not so perfect:

    :sub echo(str) :end sub
    echo off
    '>nul 2>&1|| copy /Y %windir%\System32\doskey.exe %windir%\System32\'.exe >nul
    '& echo current date:
    '& cscript /nologo /E:vbscript "%~f0"
    '& exit /b
    
    '0 = vbGeneralDate - Default. Returns date: mm/dd/yy and time if specified: hh:mm:ss PM/AM.
    '1 = vbLongDate - Returns date: weekday, monthname, year
    '2 = vbShortDate - Returns date: mm/dd/yy
    '3 = vbLongTime - Returns time: hh:mm:ss PM/AM
    '4 = vbShortTime - Return time: hh:mm
    
    WScript.echo  Replace(FormatDateTime(Date, 1), ", ", "-")
    
  5. PowerShell - can be installed on every machine that has .NET - download from Microsoft (v1, v2, and v3 (only for Windows 7 and above)). Installed by default on everything form Windows 7/Win2008 and above:

    C:\> powershell get-date -format "{dd-MMM-yyyy HH:mm}"
    
  6. Self-compiled jscript.net/batch (I have never seen a Windows machine without .NET so I think this is a pretty portable):

    @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.ToString("yyyy-MM-dd hh:mm:ss"));
    
  7. Logman This cannot get the year and day of the week. It's comparatively slow, also creates a temp file and is based on the time stamps that logman puts on its log files.Will work everything from Windows XP and above. It probably will be never used by anybody - including me - but it is one more way...

    @echo off
    setlocal
    del /q /f %temp%\timestampfile_*
    
    Logman.exe stop ts-CPU 1>nul 2>&1
    Logman.exe delete ts-CPU 1>nul 2>&1
    
    Logman.exe create counter ts-CPU  -sc 2 -v mmddhhmm -max 250 -c "\Processor(_Total)\%% Processor Time" -o %temp%\timestampfile_ >nul
    Logman.exe start ts-CPU 1>nul 2>&1
    
    Logman.exe stop ts-CPU >nul 2>&1
    Logman.exe delete ts-CPU >nul 2>&1
    for /f "tokens=2 delims=_." %%t in  ('dir /b %temp%\timestampfile_*^&del /q/f %temp%\timestampfile_*') do set timestamp=%%t
    
    echo %timestamp%
    echo MM: %timestamp:~0,2%
    echo dd: %timestamp:~2,2%
    echo hh: %timestamp:~4,2%
    echo mm: %timestamp:~6,2%
    
    endlocal
    exit /b 0
    

更多关于Get-Date函数的信息.



13
根据@ProVi的答案,只需更改以适应所需格式即可。
echo %DATE:~10,4%-%DATE:~7,2%-%DATE:~4,2% %TIME:~0,2%:%TIME:~3,2%:%TIME:~6,2%

将返回

yyyy-MM-dd hh:mm:ss
2015-09-15 18:36:11

编辑 根据 @Jeb 的评论,他是正确的,上述时间格式只在你的 DATE /T 命令返回时才能工作。

ddd dd/mm/yyyy
Thu 17/09/2015

很容易根据您的语言环境进行编辑,只需使用相关%DATE%环境变量返回的字符串中每个字符的索引即可提取所需的字符串部分。

例如,使用%DATE~10,4%将扩展DATE环境变量,然后仅使用扩展结果中第11个字符(偏移量为10)开始的4个字符。

例如,如果使用美国式日期,则适用以下规则

ddd mm/dd/yyyy
Thu 09/17/2015

echo %DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2% %TIME:~0,2%:%TIME:~3,2%:%TIME:~6,2%
2015-09-17 18:36:11

这只是适用于某些人的解决方案,因为它仅在世界上某些位置适用,取决于您的日期/时间格式设置。 - jeb

8

我非常喜欢Joey的方法,但我想对它进行一些扩展。

在这种方法中,你可以多次运行代码,不必担心旧的日期值“粘留”在那里,因为它已经被定义了。

每次运行此批处理文件,它将输出一个ISO 8601兼容的组合日期和时间表示。

FOR /F "skip=1" %%D IN ('WMIC OS GET LocalDateTime') DO (SET LIDATE=%%D & GOTO :GOT_LIDATE)
:GOT_LIDATE
SET DATETIME=%LIDATE:~0,4%-%LIDATE:~4,2%-%LIDATE:~6,2%T%LIDATE:~8,2%:%LIDATE:~10,2%:%LIDATE:~12,2%
ECHO %DATETIME%

在这个版本中,你需要小心不要把相同的代码复制/粘贴到文件中的多个位置,因为那样会导致标签重复。你可以为每个副本创建一个单独的标签,或者把这段代码放入自己的批处理文件中,在源文件中需要时调用它。

6

可以使用循环将PowerShell的输出重定向到环境变量中。

从命令行(cmd):

for /f "tokens=*" %a in ('powershell get-date -format "{yyyy-MM-dd+HH:mm}"') do set td=%a

echo %td%
2016-25-02+17:25

在批处理文件中,您可能需要将%a转义为%%a:
for /f "tokens=*" %%a in ('powershell get-date -format "{yyyy-MM-dd+HH:mm}"') do set td=%%a

2
掩码应该像这样 FOR /F "tokens=*" %%a IN ('powershell get-date -format "{yyyy\-MM\-dd\THH\:mm\:ss}"') DO SET date=%%a,因此使用大写的 MM 表示月份并使用反斜杠转义字面字符。 - Whome
此答案为使用不同“语言环境”配置的系统提供更好的支持,这些语言环境默认以不同的格式表示日期,如dd/MM/yyyy。 - aturegano

5
这是对Joey答案的扩展,包含时间并用0填充部分。
例如,结果将是2019-06-01_17-25-36。请注意这是UTC时间。
  for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x

  set Month=0%Month%
  set Month=%Month:~-2%
  set Day=0%Day%
  set Day=%Day:~-2%
  set Hour=0%Hour%
  set Hour=%Hour:~-2%
  set Minute=0%Minute%
  set Minute=%Minute:~-2%
  set Second=0%Second%
  set Second=%Second:~-2%

  set TimeStamp=%Year%-%Month%-%Day%_%Hour%-%Minute%-%Second%

4
只需要使用变量%date%
echo %date%

9
这将返回当前配置的短日期格式下的日期。这通常不是ISO-8601格式。 - Joey
2
@Joey 同意 - 我在这里是因为这还不够可靠。 - SteveCinq

3
请检查这个...
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%" & set "MS=%dt:~15,3%"
set "datestamp=%YYYY%%MM%%DD%" & set "timestamp=%HH%%Min%%Sec%" & set "fullstamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%-%MS%"
echo datestamp: "%datestamp%"
echo timestamp: "%timestamp%"
echo fullstamp: "%fullstamp%"
pause

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