Format date and time in a Windows batch script

Viewed 1001789

In a Windows (Windows XP) batch script I need to format the current date and time for later use in files names, etc.

It is similar to Stack Overflow question How to append a date in batch files, but with time in as well.

I have this so far:

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%

which gives:

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

Is there a way I can allow for a single digit hour in %TIME%, so I can get the following?

2009_07_28__08_36_01
37 Answers

I ended up with this script:

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%

:: On WIN2008R2 e.g. I needed to make your 'set month=%date:~3,2%' like below ::otherwise 00 appears for MONTH

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%

As has been noted, parsing the date and time is only useful if you know the format being used by the current user (for example, MM/dd/yy or dd-MM-yyyy just to name two). This could be determined, but by the time you do all the stressing and parsing, you will still end up with some situation where there is an unexpected format used, and more tweaks will be be necessary.

You can also use some external program that will return a date slug in your preferred format, but that has disadvantages of needing to distribute the utility program with your script/batch.

There are also batch tricks using the CMOS clock in a pretty raw way, but that is tooo close to bare wires for most people, and also not always the preferred place to retrieve the date/time.

Below is a solution that avoids the above problems. Yes, it introduces some other issues, but for my purposes I found this to be the easiest, clearest, most portable solution for creating a datestamp in .bat files for modern Windows systems. This is just an example, but I think you will see how to modify for other date and/or time formats, etc.

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

The following may not be a direct answer but a close one?

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%

At least it may be inspiring.

The offset:length formatting supported with the SET command in Windows will not allow you to pad the 0 as you seem to be interested in.

However, you can code a BATCH script to check for the hour being less than 10 and
pad accordingly with a different echo string.

You will find some information on the SET command on this link.


You can also change to other programming methods to get here.

It is quite simple in unix bash (available with Cygwin on Windows) to just say,

date +%Y_%m_%d__%H_%M_%S

And, it always pads correctly.

set hourstr = %time:~0,2%
if "%time:~0,1%"==" " (set hourstr=0%time:~1,1%)
set datetimestr=%date:~0,4%%date:~5,2%%date:~8,2%-%hourstr%%time:~3,2%%time:~6,2%

This script use a WMI interface accessed primary via WMIC tool, which is an integral part of Windows since Windows XP Professional (Home edition is supported too, but the tool is not installed by default). The script also implements a workaround of missing WMIC tool by creating and calling a WSH vbscript for access a WMI interface and write to console output the time with same format as WMIC tool provide.

@ECHO OFF
REM Returns: RETURN
REM Modify:  RETURN, StdOut
REM Required - mandatory: none
REM Required - optionaly: format strings delimited by a space to format an output delimited by predefined delimiter
REM    YYYY = 4-digit year
REM      MM = 2-digit month
REM      DD = 2-digit day
REM      hh = 2-digit hour
REM      mm = 2-digit minute
REM      ss = 2-digit second
REM      ms = 3-digit millisecond

CALL :getTime %*
ECHO %RETURN%
GOTO :EOF


REM SUBROUTINE
REM Returns: RETURN
REM Modify:  RETURN
REM Required - mandatory: none
REM Required - optionaly: format strings delimited by a space to format an output delimited by predefined delimiter
REM    YYYY = 4-digit year
REM      MM = 2-digit month
REM      DD = 2-digit day
REM      hh = 2-digit hour
REM      mm = 2-digit minute
REM      ss = 2-digit second
REM      ms = 3-digit millisecond
:getTime
  SETLOCAL EnableDelayedExpansion
    SET DELIM=-
    WHERE /Q wmic.exe
    IF NOT ERRORLEVEL 1 FOR /F "usebackq skip=1 tokens=*" %%x IN (`wmic.exe os get LocalDateTime`) DO (SET DT=%%x & GOTO getTime_Parse)
    SET _TMP=%TEMP:"=%
    ECHO Wscript.StdOut.WriteLine (GetObject("winmgmts:root\cimv2:Win32_OperatingSystem=@").LocalDateTime)>"%_TMP%\get_time_local-helper.vbs"
    FOR /F "usebackq tokens=*" %%x IN (`cscript //B //NoLogo "%_TMP%\get_time_local-helper.vbs"`) DO (SET DT=%%x & GOTO getTime_Parse)
    :getTime_Parse
      SET _RET=
      IF "%1" EQU "" (
        SET _RET=%DT:~0,4%%DELIM%%DT:~4,2%%DELIM%%DT:~6,2%%DELIM%%DT:~8,2%%DELIM%%DT:~10,2%%DELIM%%DT:~12,2%%DELIM%%DT:~15,3%
      ) ELSE (
        REM Not recognized format strings are ignored during parsing - no error is reported.
       :getTime_ParseLoop
         SET _VAL=
         IF "%1" EQU "YYYY" SET _VAL=%DT:~0,4%
         IF "%1" EQU "MM"   SET _VAL=%DT:~4,2%
         IF "%1" EQU "DD"   SET _VAL=%DT:~6,2%
         IF "%1" EQU "hh"   SET _VAL=%DT:~8,2%
         IF "%1" EQU "mm"   SET _VAL=%DT:~10,2%
         IF "%1" EQU "ss"   SET _VAL=%DT:~12,2%
         IF "%1" EQU "ms"   SET _VAL=%DT:~15,3%
         IF DEFINED _VAL (
           IF DEFINED _RET (
             SET _RET=!_RET!%DELIM%!_VAL!
           ) ELSE (
             SET _RET=!_VAL!
           )
         )
         SHIFT
         IF "%1" NEQ "" GOTO getTime_ParseLoop
      )
  ENDLOCAL & SET RETURN=%_RET%
GOTO :EOF

A nice single-line trick to avoid early variable expansion is to use cmd /c echo ^%time^%

cmd /c echo ^%time^% & dir /s somelongcommand & cmd /c echo ^%time^%

So the problem with %DATE% is that it depends on locale. So most of the previous answers did not work for me. If you are not picky about the exact format and just want a timestamp to differentiate the files you can do this:

set _date=%DATE%-%TIME%
set _date=%_date:/=-%
set _date=%_date: =-%
set _date=%_date::=-%
set _date=%_date:.=-%
echo %_date%

This should work for most locales. If it doesn't add another line set _date=%_date:<offending_char>=-% to remove the offending character. ie: a character which is not compatible with filenames or something you don't want in the file name.

enter image description here

enter image description here

Please note this doesn't meet the exact criteria laid down by the question.

  1. set xtime=%time%
  2. if "%xtime:~0,1%" == " " set xtime=0%xtime:~1,7%
  3. set isodate=%date:~-4%%date:~3,2%%date:~0,2%_%xtime:~0,2%%xtime:~3,2%%time:~6,2%

Hope this helps:

set MM=%date:~4,2%
set DD=%date:~7,2%
set YYYY=%date:~10,4%

echo %DD%_%MM%_%YYYY%

This will print 05_06_2021

for /f "tokens=1-4 delims=/ " %%I in ("%DATE%") do set curdate=%%K_%%J_%%I
for /f "tokens=1-4 delims=:," %%I in ("%TIME: =0%") do set curtime=%%I_%%J_%%K
echo %curdate%__%curtime%

replace delims symbols if your system uses another (used for slicing to %%I,%%J...)
also edit curdate if your system uses another D/M/Y order

Related