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

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

Unix 外壳类似物:

today=`date +%F`
echo $today
259292 次浏览

您可以使用

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

Then you can extract the individual parts using substrings:

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%

Much nicer than fiddling with substrings, at the expense of polluting your variable namespace.

如果需要 UTC 而不是本地时间,命令大致相同:

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

只需使用 %date%变量:

echo %date%

我真的很喜欢乔伊的方法,但我觉得我应该扩展一下。

在这种方法中,您可以多次运行代码,而不必担心旧的日期值“停留不前”,因为它已经定义好了。

每次运行此批处理文件时,它都会输出兼容 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%

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

如果您希望在批处理文件中使用标准的 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个变量: Day (dd)、 Month (mm)和 Year (yyyy)。然后您可以根据需要在以后的批处理脚本中使用它们。

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

While I understand an answer has been accepted for this question this alternative method may be appreciated by many looking to achieve this without using the WMI console, so I hope it adds some value to this question.

Two more ways that do not depend on the time settings (both taken from 如何获得独立于本地化的数据/时间). And both also get the day of the week and none of them requires admin permissions!:

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

    @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 混合(需要保存为 .bat)。作为 Windows Script Host(though can be disabled through the registry it's a rare case)的一部分,从 视窗 NT及以上版本的每个系统上都可以使用 JScript:

    @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
    

More information about the Get-Date function.


I set an environment variable to the value in the numeric format desired by doing this:

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

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

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

will return

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

如果你不介意一次性投资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. 您可以使用任何 VisualStudio 版本(如 VisualStudioExpress)来生成 FormatNow.exe。
  2. 在 Visual Studio 中,选择“控制台应用”C # 项目,而不是“ Windows 窗体应用程序”项目。
  3. 常识: 构建的 FormatNow.exe 需要.NET Framework 才能运行。
  4. 常识: 将 FormatNow.exe 添加到 PATH 变量后,需要重新启动 CMD 才能生效。它还适用于环境变量的任何更改。

好处:

  1. 它不慢(在0.2秒内完成)。
  2. 支持多种格式 < a href = “ https://msdn.microsoft.com/en-us/library/8kb3ddd4(v = vs. 110) . aspx”rel = “ nofollow”> https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx 例如,FormatNow“ ddd”只获取星期几,FormatNow“ yyyy”只获取年份
  3. 它不依赖于 Windows 的区域设置,所以它的输出更加可靠。另一方面,% date% 在不同的计算机上没有提供一致的格式,并且不可靠。
  4. You don't need to create so many CMD variables and pollute the variable namespace.
  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 批处理脚本的糟糕功能,而对于许多简单的任务都需要变通方法?为什么我们要使用错误的工具?

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

If the date format is Thu 17/03/2016 use like this:

set datestr=%date:~10,4%-%date:~7,2%-%date:~4,2%
echo %datestr%
echo %DATE:~10,4%%DATE:~7,2%%DATE:~4,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

看看这个。

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

如果您已经安装了 Python,那么可以这样做

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

您可以很容易地根据需要调整格式字符串。

由于日期和时间格式是位置特定的信息,从% 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

Result:
2018-04-25 _ 10:03:11

这是乔伊的答案的一个延伸,包括时间和填充的零件与0。

例如,结果将是2019-06-01 _ 17-25-36。

  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%

我使用以下方法:

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

如果 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