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

Windows batch: formatted date into variable

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

Unix shell模拟:

1
2
today=`date +%F`
echo $today


您可以使用与区域设置无关的方式获取当前日期

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

然后,您可以使用子字符串提取单个部分:

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

另一种方法,即获得包含各个部分的变量,将是:

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

比摆弄子串更好,代价是污染你的变量命名空间。

如果您需要UTC而不是本地时间,则命令或多或少相同:

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


如果您希望在批处理文件中使用标准MS-DOS命令实现此目的,那么您可以使用:

1
2
3
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

我确信这可以进一步改进,但这会将日期分为3个变量,分别为Day(dd),Month(mm)和Year(yyyy)。然后,您可以根据需要在批处理脚本中使用它们。

1
2
3
4
5
SET todaysdate=%yyyy%%mm%%dd%
echo %dd%
echo %mm%
echo %yyyy%
echo %todaysdate%

虽然我理解这个问题已经接受了答案,但是许多人希望在不使用WMI控制台的情况下实现这一目标,所以我希望它能为这个问题增加一些价值。


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

如果日期格式为"Thu 03/03/2016",请使用如下:

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


另外两种不依赖于时间设置的方法(均来自如何获取数据/时间与本地化无关)。而且两者都得到了一周的日子,而且没有一个需要管理员权限!:

  • MAKECAB - 将在每个Windows系统上工作(快速,但创建一个小的临时文件)(foxidrive脚本):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @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
  • ROBOCOPY - 它不是Windows XP和Windows Server 2003的本机命令,但可以从Microsoft站点下载。但它内置于Windows&nbsp; Vista及以上版本的所有内容中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @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

    还有三种使用其他Windows脚本语言的方法。他们会给你更多的灵活性,例如你可以得到一年中的一周,时间以毫秒为单位,等等。

  • JScript / BATCH混合(需要保存为.bat)。作为Windows脚本宿主的一部分,JScript在Windows NT及更高版本的每个系统上都可用(虽然可以通过注册表禁用它是一种罕见的情况):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @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());
  • VBScript / BATCH混合(是否可以在不使用临时文件的情况下在批处理文件中嵌入和执行VBScript?)与jscript相同的情况,但是杂交并不是那么完美:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    :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),",","-")
  • PowerShell - 可以安装在每台具有.NET的计算机上 - 从Microsoft下载(v1,v2和v3(仅适用于Windows&nbsp; 7及以上版本))。默认安装在Windows&nbsp; 7 / Win2008及以上版本的所有内容中:

    1
    C:\> powershell get-date -format"{dd-MMM-yyyy HH:mm}"
  • 自编的jscript.net/batch(我从未见过没有.NET的Windows机器所以我认为这是一个非常便携的):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    @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"));
  • Logman这不能得到一周中的一年和一天。它相对较慢,也会创建一个临时文件,并基于logman放在其日志文件上的时间戳。将从Windows&nbsp; XP及以上版本开始工作。它可能永远不会被任何人使用 - 包括我 - 但它还有一种方式......

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @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功能的更多信息。


    我真的很喜欢Joey的方法,但我想我会稍微扩展一下。

    在这种方法中,您可以多次运行代码,而不必担心旧的日期值"粘附",因为它已经定义。

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

    1
    2
    3
    4
    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%

    在此版本中,您必须小心不要将相同的代码复制/粘贴到文件中的多个位置,因为这会导致重复的标签。您可以为每个副本设置单独的标签,或者只是将此代码放入其自己的批处理文件中,并在必要时从源文件中调用它。


    只需使用%date%变量:

    1
    echo %date%


    根据@ProVi的回答,只需更改以适应您需要的格式

    1
    echo %DATE:~10,4%-%DATE:~7,2%-%DATE:~4,2% %TIME:~0,2%:%TIME:~3,2%:%TIME:~6,2%

    将返回

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

    编辑
    根据@Jeb评论,谁是正确的,上述时间格式只有在你的DATE / T命令返回时才有效

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

    可以很容易地编辑以适合您的语言环境,但是,通过使用相关%DATE%环境变量返回的字符串中每个字符的索引,您可以提取所需字符串的部分。

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

    例如,如果使用美国风格的日期,则以下适用

    1
    2
    3
    4
    5
    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


    我通过这样做将环境变量设置为所需的数字格式的值:

    1
    FOR /F"tokens=1,2,3,4 delims=/" %a IN ('echo %date%') DO set DateRun=%d-%b-%c

    如果您安装了Python,则可以执行此操作

    1
    python -c"import datetime;print(datetime.date.today().strftime('%Y-%m-%d'))"

    您可以轻松地根据需要调整格式字符串。


    检查一下......

    1
    2
    3
    4
    5
    6
    7
    8
    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

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

    从命令行(cmd):

    1
    2
    3
    4
    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

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


    由于日期和时间格式是特定于位置的信息,从%date%和%time%变量中检索它们将需要额外的努力来解析格式转换的字符串。一个好主意是使用一些API来检索数据结构并根据需要进行解析。 WMIC是一个不错的选择。下面的例子使用Win32_LocalTime。您还可以使用Win32_CurrentTime或Win32_UTCTime。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @echo off  
    SETLOCAL ENABLEDELAYEDEXPANSION  
    for /f %%x in ('wmic path Win32_LocalTime get /format:list ^| findstr"="') do set %%x  
    set yyyy=0000%Year%  
    set mmmm=0000%Month%  
    set dd=00%Day%  
    set hh=00%Hour%  
    set mm=00%Minute%  
    set ss=00%Second%  
    set ts=!yyyy:~-4!-!mmmm:~-2!-!dd:~-2!_!hh:~-2!:!mm:~-2!:!ss:~-2!  
    echo %ts%  
    ENDLOCAL

    结果:
    2018-04-25_10:03:11


    这是Joey的答案的延伸,包括时间和填充0的部分。

    例如,结果将是2019-06-01_17-25-36。 另请注意,这是UTC时间。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      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%

    1
    echo %DATE:~10,4%%DATE:~7,2%%DATE:~4,2%


    如果您不介意一次性投资10到30分钟以获得可靠的解决方案(不依赖于Windows的区域设置),请继续阅读。

    让我们释放思绪。你想简化脚本看起来像这样吗? (假设您要设置LOG_DATETIME变量)

    1
    2
    3
    4
    5
    FOR /F"tokens=* USEBACKQ" %%F IN (`FormatNow"yyyy-MM-dd"`) DO (
      Set LOG_DATETIME=%%F
    )

    echo I am going to write log to Testing_%LOG_DATETIME%.log

    您可以。只需使用C#.NET构建FormatNow.exe并将其添加到PATH即可。

    笔记:

  • 您可以使用任何Visual Studio版本(如Visual Studio Express)来构建FormatNow.exe。
  • 在Visual Studio中,选择"控制台应用程序"C#项目,而不是"Windows窗体应用程序"项目。
  • 常识:构建的FormatNow.exe需要.NET Framework才能运行。
  • 常识:将FormatNow.exe添加到PATH变量后,需要重启CMD才能生效。它也适用于环境变量的任何变化。
  • 优点:

  • 它不慢(在0.2秒内完成)。
  • 支持多种格式https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
    例如FormatNow"ddd"只获取星期几,FormatNow"yyyy"只获得一年
  • 它不依赖于Windows的区域设置,因此其输出更可靠。另一方面,%date%不会在不同的计算机上提供一致的格式,并且不可靠。
  • 您不需要创建这么多CMD变量并污染变量名称空间。
  • 批处理脚本中需要3行来调用程序并获得结果。它应该足够短。
  • 我使用Visual Studio 2010构建的FormatNow.exe的源代码(我更喜欢自己构建它以避免下载未知的,可能是恶意程序的风险)。只需复制并粘贴下面的代码,构建程序一次,然后您就拥有了一个可靠的日期格式化程序,以备将来使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Globalization;

    namespace FormatNow
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    if (args.Length < 1)
                    {
                        throw new ArgumentException("Missing format");
                    }
                    string format = args[0];
                    Console.Write(DateTime.Now.ToString(format, CultureInfo.InvariantCulture.DateTimeFormat));
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }

        }
    }

    通常,在处理复杂的逻辑时,我们可以通过构建一个非常小的程序并调用程序将输出捕获回批处理脚本变量来简化它。我们不是学生,我们没有参加考试,要求我们遵循批处理脚本专用规则来解决问题。在实际工作环境中,允许任何(合法)方法。为什么我们仍然要坚持Windows批处理脚本的不良功能,需要解决许多简单任务的变通方法?我们为什么要使用错误的工具来完成这项工作?