Search code examples
windowsbatch-filecmdrenamebatch-rename

Windows CMD Batch Timestamp WITH SECONDS


I need to batch append a date modified timestamp to a filenames in Windows 10. I am almost there.

The answer here was extremely helpful in getting me nearly to my objective.

The batch script below creates appends the file's date modified, but omits the seconds YYYYMMDDHHMM instead of YYYYMMDDHHMMSS (what I need).

My computer's date format is YYYY-MM-DD, and time format hh:mm:ss.

How can I achieve this?

@echo off
FOR /R "J:\PHP Member Reports\Test" %%Z IN (*.TRN) DO @( 
    FOR /F "Tokens=1-6 delims=:-\/. " %%A IN ("%%~tZ") DO @(
        ren "%%~dpnxZ" "%%~A%%~B%%~C%%~D%%~E%%~F_%%~nZ%%~xZ"
    )
)

Solution

  • It is necessary to use wmic – the Windows Management Instrumentation Command-line utility – to get last modification date of a file also with second.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    set "RenameError=0"
    for /F "delims=" %%I in ('dir "J:\PHP Member Reports\Test\*.trn" /A-D-H /B /S 2^>nul') do call :ProcessFile "%%I"
    if %RenameError% == 1 echo/ & pause
    endlocal
    goto :EOF
    
    :ProcessFile
    set "FileName=%~1"
    set "FileName=%FileName:\=\\%"
    set "FileDate="
    
    rem Get last modification date of current file using Windows Management
    rem Instrumentation Command-line utility (WMIC) which requires that each
    rem backslash is escaped with a backslash.
    for /F "usebackq tokens=2 delims==." %%T in (`%SystemRoot%\System32\wbem\wmic.exe DATAFILE where "name='%FileName%'" GET LastModified /VALUE 2^>nul`) do set "FileDate=%%T"
    if defined FileDate goto RenameFile
    
    rem The command line above fails if a comma exists anywhere in
    rem file name with full path. Use in this case a different syntax.
    if not defined FileDate for /F "usebackq tokens=2 delims==." %%T in (`%SystemRoot%\System32\wbem\wmic.exe DATAFILE where (name^="%FileName%"^) GET LastModified /VALUE 2^>nul`) do set "FileDate=%%T"
    if defined FileDate goto RenameFile
    
    rem The command line above fails again if there is a comma and additionally
    rem also a closing parenthesis in file name with full path. To workaround
    rem this issue copy the file with name WmicFile.tmp to the directory for
    rem temporary files of which path does not contain usually , and ) at the
    rem same time and get last modification date from this file before deleting
    rem this temporary file.
    
    copy "%~1" "%TEMP%\WmicFile.tmp" >nul
    set "FileName=%TEMP%\WmicFile.tmp"
    set "FileName=%FileName:\=\\%"
    for /F "usebackq tokens=2 delims==." %%T in (`%SystemRoot%\System32\wbem\wmic.exe DATAFILE where "name='%FileName%'" GET LastModified /VALUE 2^>nul`) do set "FileDate=%%T"
    del "%TEMP%\WmicFile.tmp"
    if defined FileDate goto RenameFile
    
    if %RenameError% == 1 echo/
    echo ERROR: Failed to determine last modification date of file
    echo        %1
    set "RenameError=1"
    goto :EOF
    
    :RenameFile
    set "FileName=%~n1"
    rem Do nothing if current file name ends already with determined date/time.
    if "%FileName:~-15%" == "_%FileDate%" goto :EOF
    rem Rename the file with appending after an underscore the
    rem last modification date and time in format YYYYMMDDhhmmss.
    ren "%~1" "%~n1_%FileDate%%~x1" 2>nul
    if not errorlevel 1 goto :EOF
    
    if %RenameError% == 1 echo/
    echo ERROR: Failed to rename the file
    echo        %1
    echo        to "%~n1_%FileDate%%~x1"
    set "RenameError=1"
    goto :EOF
    

    It is no good idea to use file names retrieved by command FOR itself from a directory or directory tree on renaming, moving, deleting or copying files in directories searched by FOR. This can very easily result in omitting files or processing some files multiple times because of list of entries in a searched directory changes while FOR processes the directory entries. It is strongly recommended to process a list of file names by FOR get completely before starting processing the files, especially on FAT drives (FAT16, FAT32, exFat) on which the file names are returned not sorted at all by the file system.

    The command DIR is executed by FOR in a background command process started with cmd.exe /C which outputs to handle STDOUT only all non hidden files in specified directory and its subdirectories matching the wildcard pattern *.trn. This list of file names each with full path is captured by FOR. Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.

    Each file name with full path is passed by FOR to subroutine ProcessFile enclosed in double quotes to work also for file names/paths containing a space or one of these characters &()[]{}^=;!'+,`~.

    The WMIC syntax requires that each file name is specified with full path and each backslash in file path is escaped with a backslash. See also my answer on Find out if file is older than 4 hours in batch file.

    How to escape both comma and closing parenthesis in WHERE clause of WMIC? explains that a full file name containing a comma , or a closing parenthesis ) is problematic. The batch file is written to work around those problems. It can be expected that first executed FOR command line with WMIC is nearly always already successful on determining last modification date of file with second.

    The batch file is written to output an error message if last modification date could not be determined for a file.

    No rename is executed if a file name ends already with an underscore and the right last modification date/time.

    It is verified by the batch file if rename operation was successful with displaying an error message on failed file rename.

    Note: The batch file is not written to replace YYYYMMDDhhmmss at end of a file name by correct last modification date/time of this file. This was not required in question.

    The batch file halts execution at end with command PAUSE if any error occurred within subroutine ProcessFile. Otherwise the execution of the batch file ends without any user information output to STDOUT (console window).

    Please note that WMIC needs quite a long time to finish the operation. So on a large list of files this batch file can take several minutes to complete.

    For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

    • call /?
    • copy /?
    • del /?
    • dir /?
    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • if /?
    • pause /?
    • rem /?
    • ren /?
    • set /?
    • setlocal /?
    • wmic /?
    • wmic datafile /?
    • wmic datafile get /?
    • wmic datafile get "last modified" /?
    • wmic datafile where /?

    See also: