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


105

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

Unix shell模拟:

today=`date +%F`
echo $today



1
阿达希尔(Adarshr),该问题的答案使用一种非常可怕且易于出错的方式来处理。我建议不要使用它。
乔伊(Joey)2012年

该链接有助于理解以下答案。ss64.com/nt/for_f.html
smwikipedia's

Answers:


151

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

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=在两者之间使用来解决。我猜这就是user2023861偶然发现的。
乔伊

1
@CharlesWood,至少我努力在自己的批处理文件中追求鲁棒性,尽管这些天我经常使用PowerShell。
乔伊

1
:将要设置变量YearMonthDayHourMinuteSecondQuarterWeekInMonthDayOfWeek
用户

2
for /f %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set %%x set today=%Year%-%Month%-%Day% 答案无效:它返回一个数字的月份和日期。如何获得2位数左填充零日期和日期到目前为止的字符串?
安德鲁斯(Andrus)

38

如果要在批处理文件中使用标准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

我敢肯定,这可以进一步改善,但这会将日期分为3个变量,分别是日(dd),月(mm)和年(yyyy)。然后,您可以根据需要稍后在批处理脚本中使用它们。

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

虽然我知道此问题的答案已被接受,但许多希望在不使用WMI控制台的情况下实现此目标的人可能会喜欢这种替代方法,因此,我希望它为该问题增加了一些价值。


3
我发现我需要在Windows 7盒子上稍作更改。令牌需要增加一个:... FOR / F“令牌= 2,3,4 eol = / DELIMS = /” ...
Joe Johnston

1
在Azure上的Win Server 2012上相同
Kirill Yunussov '16

34

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

如果日期格式是这样Thu 17/03/2016使用的:

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

1
这是最接近问题的答案。我只需要一个简单的代码即可,而不是程序。
DCookie

2
同意 这里的一些答案几乎就像“安装MS SQL Server,连接SQL Client并执行命令SELECT CONVERT(VARCHAR(16), GETDATE(), 112)”。
isapir

2
ISO-8601格式的日期时间是%date:~10,4%%date:~7,2%%date:~4,2%T%time:~0,2%%time:~3,2%%time:~6,2%
isapir

3
与其它反应看起来像一个程序的原因是,这个答案虽然简单,但会如果在路上没有配置您的Windows区域设置,该代码预期失败(即此代码将在不工作的每一个 Windows系统上)
丹尼尔·斯科特

20

另外两种不依赖于时间设置的方式(均来自“ 如何获取与本地化无关的数据/时间”)。两者都可以获取星期几,而且都不需要管理员权限!:

  1. MAKECAB-将在每个Windows系统上运行(速度很快,但会创建一个小的临时文件)(foxidrive脚本):

    @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-这不是Windows XPWindows Server 2003的本机命令,但可以从Microsoft网站下载。但是它内置在Windows Vista及更高版本中的所有内容中:

    @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脚本语言的方式。它们将为您提供更大的灵活性,例如,您可以获取一年中的星期,毫秒等时间。

  3. JScript / BATCH混合(需要另存为.bat)。作为Windows Script Host的一部分,JScript在Windows NT及更高版本的每个系统上都可用(尽管可以通过注册表禁用,但这种情况很少见):

    @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混合(是否可以在不使用临时文件的情况下在批处理文件中嵌入和执行VBScript?情况下)与jscript相同,但是混合并不是那么完美:

    :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-可以安装在每个具有.NET的计算机上-从Microsoft下载(v1v2v3(仅适用于Windows 7及更高版本))。默认安装在Windows 7 / Win2008及更高版本上的所有版本上:

    C:\> powershell get-date -format "{dd-MMM-yyyy HH:mm}"
    
  6. 自编译的jscript.net/batch(我从未见过没有.NET的Windows机器,因此我认为这是一种可移植的工具):

    @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这无法获取年份和星期几。它相对较慢,还会创建一个临时文件,并且基于logman在其日志文件上放置的时间戳。它将适用于Windows XP及更高版本。它可能永远不会被任何人使用-包括我-但它是另一种方式...

    @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函数的更多信息



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%

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


5

只需使用%date%变量:

echo %date%

5
这将以当前配置的短日期格式返回日期。这很少是ISO-8601。
乔伊

@Joey Agreed-我在这里是因为这还不足以依靠。
SteveCinq '18 -10-17

5

根据@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 2015年

3

通过执行以下操作,我将环境变量设置为所需数字格式的值:

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

2

检查这一..

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

2

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

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

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


2
以什么方式说“使用python”是问题的答案?
Ross Presser

3
以与使用MAKECAB,ROBOCOPY,VBSCRIPT,POWERSHELL Logman以及此处可以在命令行上调用的其他建议相同的方式?
CodeKid

这可以简化为python -c "import datetime;print(datetime.date.today())",因为类的__str__方法date只是调用isoformat()
onewhaleid

2

可以使用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

1
应该是这样的遮罩,FOR /F "tokens=*" %%a IN ('powershell get-date -format "{yyyy\-MM\-dd\THH\:mm\:ss}"') DO SET date=%%a 因此在月份中使用大号MM并在反斜杠中转义文字字符。
Whome

1

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

@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


1

这是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%


0

我正在使用以下内容:

set iso_date=%date:~6,4%-%date:~3,2%-%date:~0,2%

或与日志文件名“ MyLogFileName”结合使用:

set log_file=%date:~6,4%-%date:~3,2%-%date:~0,2%-MyLogFileName

2
但是您的答案与其他16个相比有何不同或更好?并且已经有足够的提示,该解决方案仅适用于您的本地化
jeb

0

如果有powershell,则可以使用以下代码:

# get date
$BuildDate=(get-date -format "yyMMdd")
echo BuildDate=$BuildDate

# get time
$BuildTime=(get-date -format "hhmmss")
echo BuildTime=$BuildTime

结果如下:

BuildDate=200518
BuildTime=115919

-2

如果您不介意花费10到30分钟的时间来获得可靠的解决方案(与Windows的区域设置无关),请继续阅读。

让我们解放思想。您是否要简化脚本,使其看起来像这样?(假设您要设置LOG_DATETIME变量)

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中即可。

笔记:

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

好处:

  1. 它并不慢(在0.2秒内完成)。
  2. 支持多种格式https://msdn.microsoft.com/zh-cn/library/8kb3ddd4(v=vs.110).aspx 例如FormatNow“ ddd”仅获取星期几,FormatNow“ yyyy”仅获取星期几那一年
  3. 它不依赖于Windows的区域设置,因此其输出更加可靠。另一方面,%date%在不同计算机上的格式不一致,因此不可靠。
  4. 您不需要创建太多的CMD变量并污染变量名称空间。
  5. 批处理脚本中需要3行才能调用程序并获取结果。它应该足够短。

我使用Visual Studio 2010构建的FormatNow.exe的源代码(我宁愿自己构建它,以避免下载未知的,可能是恶意程序的风险)。只需复制并粘贴以下代码,一次构建该程序,然后您便拥有了一个可靠的日期格式化程序,可用于将来的所有使用。

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批处理脚本的较差功能,而这些功能需要许多简单任务的解决方法?为什么我们要为工作使用错误的工具?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.