26

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

Ira
  • 363
  • 1
  • 3
  • 4
  • 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 02 '10 at 17:55
  • A "more compact" solution would be something in another language (powershell? python? perl? WSH?). – user1686 Jun 02 '10 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 '18 at 20:14

13 Answers13

60

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

Jesse
  • 716
  • 6
  • 4
  • 1
    it works! this is the simplest solution I think.. – aerobrain Jun 30 '14 at 02: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 09 '16 at 09: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 https://ss64.com/nt/syntax-replace.html – handle Mar 02 '17 at 08: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 07 '18 at 13:02
14

My Solution was to use the following idea:

SET HOUR=%TIME:~0,2%
IF "%HOUR:~0,1%" == " " SET HOUR=0%HOUR:~1,1%
Jeff Atwood
  • 12,994
  • 20
  • 74
  • 92
Neil Ratcliffe
  • 141
  • 1
  • 3
5

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.

Joey
  • 1,823
  • 11
  • 13
3

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

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..

Jerry
  • 31
  • 1
1

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%
slm
  • 7,355
  • 16
  • 54
  • 72
David
  • 11
  • 1
0

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
Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • 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 03 '10 at 17:41
0

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

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

Muposat
  • 121
  • 9
0

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.

Quantim
  • 1,269
  • 11
  • 13
0

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
    @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
Risoos
  • 1
-2
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%"
Sven
  • 97,248
  • 13
  • 177
  • 225
Vitokhv
  • 101
  • 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 '15 at 06:49