26
votes

I came across a bug in my DOS script that uses date and time data for file naming. The problem was I ended up with a gap because the time variable didn't automatically provide leading zero for hour < 10. So running> echo %time% gives back: ' 9:29:17.88'.

Does anyone know of a way to conditionally pad leading zeros to fix this?

More info: My filename set command is:

set logfile=C:\Temp\robolog_%date:~-4%%date:~4,2%%date:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.log

which ends up being: C:\Temp\robolog_20100602_ 93208.log (for 9:23 in the morning).

This question is related to this one.

Thanks

3
  • It is possible to get padded hour value... FOR /F "TOKENS=1 DELIMS=:" %%A IN ('TIME/T') DO SET HH=%%A then replace %time:~0,2% with %HH% I was hoping for a more compact solution, but this will work.
    – Ira
    Jun 2, 2010 at 17:55
  • A "more compact" solution would be something in another language (powershell? python? perl? WSH?).
    – user1686
    Jun 2, 2010 at 19:20
  • Switched to mark Jesse's answer as the solution I use. It works with both pre-noon times to pad w/ leading 0 and also post-noon military time.
    – Ira
    May 17, 2018 at 20:14

13 Answers 13

60
votes

A very simple way is to just replace the leading space with zero:
echo %TIME: =0%
outputs:
09:18:53,45

4
  • 1
    it works! this is the simplest solution I think..
    – aerobrain
    Jun 30, 2014 at 2:01
  • Can this also be done with multiple characters? i.E. all ',', ' ' and ':'. Currently I create intermediate variables but of course, this works only because of the few numbers of replacements. For more it would be cumbersome.
    – Devolus
    Jan 9, 2016 at 9:19
  • 1
    I'm using this in a second "step" to modify the Hours: set HH=%time:~-11,2% set MM=%time:~-8,2% set SS=%time:~-5,2% set ISOTIME=%HH: =0%-%MM%-%SS% echo %ISOTIME% Also see ss64.com/nt/syntax-replace.html
    – handle
    Mar 2, 2017 at 8:40
  • +1 This is shortest/best answer. How I used: set timestring=%TIME: =0% early in sub call - then just work with timestring instead (or whatever variable you use).
    – B. Shea
    Apr 7, 2018 at 13:02
14
votes

My Solution was to use the following idea:

SET HOUR=%TIME:~0,2%
IF "%HOUR:~0,1%" == " " SET HOUR=0%HOUR:~1,1%
5
  • I like it. Simple and intuitive.
    – Ken
    Feb 12, 2014 at 20:16
  • Works on modern windows, but gives syntax error on server 2003! May 24, 2016 at 11:17
  • Works flawless on 2008+, most elegant solution. Thank you.
    – bjoster
    Dec 23, 2016 at 10:09
  • 1
    but gives syntax error on server 2003 - why you care that in 2016? Jan 24, 2017 at 23:45
  • Perfect on Windows 10 Command Prompt Jul 21, 2018 at 6:51
5
votes

Similar idea to Dennis' answer. The problem is that the width of %time% is always the same, so it inserts a space in the beginning instead of returning a shorter string.

You can get rid of that with for:

for /f "delims= " %x in ("%time%") do set T=0%x

The rest is more or less the same, then.

3
  • 2
    This solution works for > 10 but now creates '010' for 10:...
    – Devolus
    Jan 9, 2016 at 9:02
  • 3
    The answer from Jesse is the correct one... Jul 14, 2016 at 6:39
  • This is a very bad answer, it breaks down as soon as there are two digits in the hour. I can't beleive the OP selected it. Dec 14, 2017 at 12:15
3
votes

Using Jesse's Contribution, I just created a variable with the modified output. Then I reference that variable to build the hour portion.

set NantTime=%time: =0%
nant\bin\nant.exe -nologo+ -debug+ -verbose+ -D:project.config=debug /f:build\default.build -l:logs\architect-build-%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%-%NantTime:~0,2%-%time:~3,2%-%time:~6,2%.log 
pause

With the original source:

set hour=%time: =0%
set logfile=C:\Temp\robolog_%date:~-4%%date:~4,2%%date:~7,2%_%hour:~0,2%%time:~3,2%%time:~6,2%.log

Thanks Jesse. I would have voted if I had the reputation points.

1
vote

For the most compact solution implementing everything above, I think that

FOR /F "TOKENS=1-4 DELIMS=/ " %%A IN ("%DATE%") DO FOR /F "TOKENS=1-3 DELIMS=:." %%E IN ("%TIME: =0%") DO SET logfile=C:\Temp\robolog_%%D%%C%%B_%%E%%F%%G.log

would work here without adding any new lines to the script. It's perhaps less elegant than multiple command solutions, though..

1
vote

The following takes a few more lines but is clear and understandable. It saves stdout and stderr to separate files, each with a timestamp. The timestamp includes year, month, day, hour, minute, and second, in that order. Timestamps should always have the most significant date component first (year) and the least component (seconds) last. That enables files listings to be in time order. Without further ado, here is my solution.

:prepare time stamp 
set year=%date:~10,4%
set month=%date:~4,2%
set day=%date:~7,2%
set hour=%time:~0,2%
:replace leading space with 0 for hours < 10
if "%hour:~0,1%" == " "  set hour=0%hour:~1,1%
set minute=%time:~3,2%
set second=%time:~6,2%
set timeStamp=%year%.%month%.%day%_%hour%.%minute%.%second%

:run the program 
ProgramName.pl 1> RunLogs\out.%timeStamp% ^
               2> RunLogs\err.%timeStamp%
0
votes

This tacks a zero onto the beginning of the time and takes the last two digits of the hour (the minute and second start positions are shifted by one). So 3 AM becomes "03" then "03" and hour 15 becomes "015" then "15".

set T=0%time%
set T=%T:~1,2%%T:~4,2%%T:~7,2%
set D=%date:~-4%%date:~4,2%%date:~7,2%
set logfile=C:\Temp\robolog_%D%_%T%.log

Less readably:

set T=0%time%
set logfile=C:\Temp\robolog_%date:~-4%%date:~4,2%%date:~7,2%_%T:~1,2%%T:~4,2%%T:~7,2%.log
1
  • 1
    I'm not sure this works. If I run 'set T=0%time%' and it's 9:38AM, echo %T% gives back: '0 9:38:54.21', then taking %T:~1,2% gets the space, no leading 0.
    – Ira
    Jun 3, 2010 at 17:41
0
votes

One line of code will do what you need:

    IF "%Time:~0,1%" == " " SET TimeStamp=0%Time:~1,7%

For example, I use %Date% and then add a leading zero to a variable I use to determine if I need to replace the leading space with a zero for %Time%.

    ::Prepare TimeStamp variable by replacing leading space with 0 for Hours < 10
    SET TimeStamp=%Time:~0,8%
    IF "%Time:~0,1%" == " " SET TimeStamp=0%Time:~1,7%
    Echo Started on %Date$ at %TimeStamp%

    :: Insert what you are doing here...

    SET TimeStamp=%Time:~0,8%
    IF "%Time:~0,1%" == " " SET TimeStamp=0%Time:~1,7%
    ECHO Finished on %Date% at %TimeStamp%
0
votes

This creates a sortable timestamp and the second line makes sure there are no spaces for single digit hour, etc, to make it usable for scripts:

set datestamp=%date:~-4%.%date:~-10,-8%.%date:~-7,-5%_%time:~0,2%.%time:~3,2%.%time:~6,2%
set datestamp=%datestamp: =_%

Output:

2018.02.26__9.47.34

0
votes

Thanks to help from above... This is what I am using:

C:\Windows\System32>SET short=%date:~10,4%-%date:~4,2%-%date:~7,2%
C:\Windows\System32>ECHO -- Short Date: %short%
-- Short Date: 2018-06-27
C:\Windows\System32>SET long=%date:~10,4%-%date:~4,2%-%date:~7,2%_%time:~0,2%_%time:~3,2%_%time:~6,2%
C:\Windows\System32>ECHO -- Long Date: %long%
-- Long Date: 2018-06-27_10_51_43

I then have logs that are called out in Robocopy jobs like this:

There are many like this:

Robocopy C:\Users\ME\Favorites\ %usb%:\Local_PC\Favorites\ /MIR /TEE /FFT /DST /TIMFIX /W:5 /R:5 /NP /LOG+:%usb%:\Robocopy\LOG_%short%.txt

Ends job with this:

REN %usb%:\Robocopy\LOG_%short%.txt COMPLETE_LOG_%long%.log

COMPLETE_LOG_2018-06-27_10_53_54.log is the file produced at the end and it is sortable by file name.

0
votes

Jesse's answer solved my file rename problem by eliminating the space in the hour field. This is how I set my variables:

for /f "tokens=1,2,3,4 delims=/ " %%a in ("%date%") do set wday=%%a&set month=%%b&set day=%%c&set year=%%d
for /f "tokens=1,2 delims=:" %%a in ("%time: =0%") do set hour=%%a&set minute=%%b

It works like a champ; for some reason date didn't need the same treatment, but I imagine that's down to the regional settings.

0
votes
    @echo off



    call :PAD aaa,2,0,grw
    echo [[aaa=%aaa%]]
    pause




rem #### Function PAD ####
    goto :PADEND
    :PAD <var>,<length>,<padchar>,<string>
        set padtot=%~2
        set padchar=%~3
        set padString=%~4
        :StartPADLOOP
            call :len lenpadString,%padString%
            if ["%lenpadString%"] GEQ ["%padtot%"] goto :EndPADLOOP
            set padString=%padchar%%padString%
            goto :StartPADLOOP
        :EndPADLOOP
        set %~1=%padString%
    GOTO :EOF
    :PADEND


rem #### Function LEN ####
    goto :LENEND
    :LEN <var>,<string>
        set LENtempvar=%~2
        rem echo {{S:%LENtempvar%}}
        set LENCOUNT=0    
        :startLENLOOP
            if ["%LENtempvar%"] EQU [""] goto :endLENLOOP
            rem echo {{A:%LENtempvar%}}
            set LENtempvar=%LENtempvar:~0,-1%
            rem echo {{B:%LENtempvar%}}
            set /a LENCOUNT=LENCOUNT+1
        goto :startLENLOOP
        :endLENLOOP
        set %~1=%LENCOUNT%
    GOTO :EOF
    :LENEND
-2
votes
set sFolderName=%time: =0%
xcopy "%UserProfile%\Pictures\*.jpg" Y:\"%DATE%-%sFolderName:~0,2%h%time:~3,2%m%time:~6,2%s-%random%" /I /C /Y

15.06.2015-03h43m34s-5357

5357-%random%"
1
  • 5
    Although the code is appreciated, it should always have an accompanying explanation. This doesn't have to be long but it is expected.
    – peterh
    Jun 14, 2015 at 6:49

Not the answer you're looking for? Browse other questions tagged or ask your own question.