102

We have a batch job that runs every day and copies a file to a pickup folder. I want to also take a copy of that file and drop it into an archive folder with the filename

 yyyy-MM-dd.log

What's the easiest way to do this in a Windows batch job?

I'm basically looking for an equivalent of this Unix command:

cp source.log `date +%F`.log
1
  • When geting a Date String with the format you want in windows .bat files looks as bad as the solutions proposed. Quite honestly, just check what programming languages are available on the machine, e.g. java, ruby, perl or something else, and make a 5 second executable to give you what you want. I would not waste any time maintaining .bat file that requites more than one line of code for geting a date with a proper format.
    – 99Sono
    Commented Jun 27, 2016 at 11:48

20 Answers 20

120
CP source.log %DATE:~-4%-%DATE:~4,2%-%DATE:~7,2%.log

But it's locale dependent. I'm not sure if %DATE% is localized, or depends on the format specified for the short date in Windows.

Here is a locale-independent way to extract the current date from this answer, but it depends on WMIC and FOR /F:

FOR /F %%A IN ('WMIC OS GET LocalDateTime ^| FINDSTR \.') DO @SET B=%%A
CP source.log %B:~0,4%-%B:~4,2%-%B:~6,2%.log
7
  • 6
    Needed to do a bit of fiddling with the indices but this seems to have done the trick. (though not fully sure I understand the minus-index logic) %DATE:~-4%-%DATE:~-7,-5%-%DATE:~-10,-8%.log Commented Jun 30, 2009 at 16:37
  • 2
    If you wanted to use all positive indices, you could use: %DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%
    – opello
    Commented Jun 30, 2009 at 16:45
  • 3
    This does break on other locales. In my case the command returns 2014-5.-01 (when it would be 2014-05-26). So be very careful, if you publish scripts containing this!
    – amenthes
    Commented May 26, 2014 at 15:58
  • 6
    Use this for the time (removes miliseconds): %time:~-11,2%-%time:~-8,2%-%time:~-5,2%
    – MRC
    Commented Oct 1, 2014 at 12:45
  • 1
    Ran into Access denied (over an RDP session with UAC). It appears accessing wmic requires additional privileges (Remote Management Users group) or modifying the security token filtering rules due to remote UAC Commented Oct 1, 2018 at 20:32
54

This worked for me and was a filename-safe solution (though it generates a MM-dd-YYYY format):

C:\ set SAVESTAMP=%DATE:/=-%@%TIME::=-%
C:\ set SAVESTAMP=%SAVESTAMP: =%
C:\ set SAVESTAMP=%SAVESTAMP:,=.%.jpg
C:\ echo %SAVESTAMP%
[email protected]

The first command takes a DATE and replaces / with -, takes the TIME and replaces : with -, and combines them into DATE@TIME format. The second set statement removes any spaces, and the third set replaces , with . and appends the .jpg extension.

The above code is used in a little script that pulls images from a security IP Camera for further processing:

:while
set SAVESTAMP=%DATE:/=-%@%TIME::=-%
set SAVESTAMP=%SAVESTAMP: =%
set SAVESTAMP=%SAVESTAMP:,=.%.jpg
wget-1.10.2.exe --tries=0 -O %SAVESTAMP% http://admin:<password>@<ip address>:<port>/snapshot.cgi
timeout 1
GOTO while
6
  • the output on my console is 10-12-2014@14-22-59,44.jpg with a comma before the milliseconds
    – BeNdErR
    Commented Dec 10, 2014 at 13:24
  • 1
    Try adding set SAVESTAMP=%SAVESTAMP:,=.%.jpg before the echo statement. If that works I will update the answer. Commented Dec 11, 2014 at 2:27
  • 1
    This is not locale-independent. Returns 08.06.2016@15-42-20,33.jpg on my German laptop and [email protected] on my English one.
    – djk
    Commented Jun 8, 2016 at 13:45
  • 6
    But it's still neither locale independet nor it creates the correct (iso8601) format of yyyy-MM-dd
    – jeb
    Commented Jun 21, 2016 at 15:33
  • 1
    It's annoying that the first line still claims it was locale independent, just to see it's not after trying out...
    – m3tikn0b
    Commented Feb 6, 2017 at 10:19
18

For French Locale (France) ONLY, be careful because / appears in the date :

echo %DATE%
08/09/2013

For our problem of log file, here is my proposal for French Locale ONLY:

SETLOCAL
set LOGFILE_DATE=%DATE:~6,4%.%DATE:~3,2%.%DATE:~0,2%
set LOGFILE_TIME=%TIME:~0,2%.%TIME:~3,2%
set LOGFILE=log-%LOGFILE_DATE%-%LOGFILE_TIME%.txt
rem log-2014.05.19-22.18.txt
command > %LOGFILE%
8
  • Excellent! A little difficult to read, but it does allow to format the output just like you want to.
    – davitof
    Commented Mar 18, 2014 at 11:26
  • 2
    Great but be careful if you want to avoid white characters because HOUR can be 1 digit rendered like that: "_0:00" (the underline char is a space)
    – David Gras
    Commented Sep 4, 2014 at 22:53
  • 1
    I get "log-/18/. 0.Sa- 9.16.txt" for this answer.
    – ledlogic
    Commented Feb 18, 2017 at 15:17
  • @ledlogic: what's your locale? This answer is for French locale.
    – Aubin
    Commented Feb 18, 2017 at 18:24
  • 1
    Does NOT work I get this on Windows 7 - log-/05/. 0.We-18.13.tx
    – Sam B
    Commented Apr 5, 2017 at 22:14
16

Because the idea of tearing %DATE% and %TIME% apart and mashing them back together seems fragile at best, here's an alternative that uses a powershell oneliner:

for /f %i in ('powershell -c "get-date -format yyyy-MM-dd--HH-mm-ss"') do @set DATETIME=%i
set LOGFILE=my-script-%DATETIME%.txt

Reference for get-date is here, with format options for both .NET-style and UNIX-style.

0
11

I frequently use this, and put everything into a single copy command. The following copies example.txt as example_YYYYMMDD_HHMMSS.txt and of course you can modify it to suit your preferred format. The quotes are only necessary if there are any spaces in the filespec. If you want to reuse the exact same date/timestamp, you'd need to store it in a variable.

copy "{path}\example.txt" "{path}\_%date:~10,4%%date:~4,2%%date:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2%.txt"
10

Here is a locale independent solution (copy to a file named SetDateTimeComponents.cmd):

@echo off
REM This script taken from the following URL:
REM http://www.winnetmag.com/windowsscripting/article/articleid/9177/windowsscripting_9177.html

REM Create the date and time elements.
for /f "tokens=1-7 delims=:/-, " %%i in ('echo exit^|cmd /q /k"prompt $d $t"') do (
   for /f "tokens=2-4 delims=/-,() skip=1" %%a in ('echo.^|date') do (
      set dow=%%i
      set %%a=%%j
      set %%b=%%k
      set %%c=%%l
      set hh=%%m
      set min=%%n
      set ss=%%o
   )
)

REM Let's see the result.
echo %dow% %yy%-%mm%-%dd% @ %hh%:%min%:%ss%

I put all my .cmd scripts into the same folder (%SCRIPTROOT%); any script that needs date/time values will call SetDateTimeComponents.cmd as in the following example:

setlocal

@echo Initializing...
set SCRIPTROOT=%~dp0
set ERRLOG=C:\Oopsies.err

:: Log start time
call "%SCRIPTROOT%\SetDateTimeComponents.cmd" >nul
@echo === %dow% %yy%-%mm%-%dd% @ %hh%:%min%:%ss% : Start === >> %ERRLOG%

:: Perform some long running action and log errors to ERRLOG.

:: Log end time
call "%SCRIPTROOT%\SetDateTimeComponents.cmd" >nul
@echo === %dow% %yy%-%mm%-%dd% @ %hh%:%min%:%ss% : End === >> %ERRLOG%

As the example shows, you can call SetDateTimeComponents.cmd whenever you need to update the date/time values. Hiding the time parsing script in it's own SetDateTimeComponents.cmd file is a nice way to hide the ugly details, and, more importantly, avoid typos.

2
  • 2
    sorry, this is not locale-independent: on my French Windows, I get "18 -2014- @ 13:14:43"
    – davitof
    Commented Mar 18, 2014 at 11:15
  • 2
    Can confirm: not locale-independent. prompt $d $t returns 30.05.2016 15:35:56,93 on my system.
    – djk
    Commented Jun 8, 2016 at 13:36
7

This will ensure that the output is a 2-digit value...you can rearrange the output to your liking and test by un-commenting the diagnostics section. Enjoy!

(I borrowed a lot of this from other forums...)

:: ------------------ Date and Time Modifier ------------------------

@echo off
setlocal

:: THIS CODE WILL DISPLAY A 2-DIGIT TIMESTAMP FOR USE IN APPENDING FILENAMES

:: CREATE VARIABLE %TIMESTAMP%

for /f "tokens=1-8 delims=.:/-, " %%i in ('echo exit^|cmd /q /k"prompt $D $T"') do (
   for /f "tokens=2-4 skip=1 delims=/-,()" %%a in ('echo.^|date') do (
set dow=%%i
set %%a=%%j
set %%b=%%k
set %%c=%%l
set hh=%%m
set min=%%n
set sec=%%o
set hsec=%%p
)
)

:: ensure that hour is always 2 digits

if %hh%==0 set hh=00
if %hh%==1 set hh=01
if %hh%==2 set hh=02
if %hh%==3 set hh=03
if %hh%==4 set hh=04
if %hh%==5 set hh=05
if %hh%==6 set hh=06
if %hh%==7 set hh=07
if %hh%==8 set hh=08
if %hh%==9 set hh=09


:: --------- TIME STAMP DIAGNOSTICS -------------------------

:: Un-comment these lines to test output

:: echo dayOfWeek = %dow%
:: echo year = %yy%
:: echo month = %mm%
:: echo day = %dd%
:: echo hour = %hh%
:: echo minute = %min%
:: echo second = %sec%
:: echo hundredthsSecond = %hsec%
:: echo.
:: echo Hello! 
:: echo Today is %dow%, %mm%/%dd%. 
:: echo.
:: echo. 
:: echo.
:: echo.
:: pause

:: --------- END TIME STAMP DIAGNOSTICS ----------------------

:: assign timeStamp:
:: Add the date and time parameters as necessary - " yy-mm-dd-dow-min-sec-hsec "

endlocal & set timeStamp=%yy%%mm%%dd%_%hh%-%min%-%sec%
echo %timeStamp%
0
2

Create a file with the current date as filename (ex. 2008-11-08.dat)

echo hello > %date%.dat    

With the current date but without the "-" (ex. 20081108.dat)

echo hello > %date:-=%.dat   
2

Maybe this can help:

echo off
@prompt set date=$d$_ set time=$t$h$h$h
echo some log >> %date% %time%.log
exit

or

echo off
set v=%date%.log
echo some log >> %v%
5
  • Nice one Secko... that %date% value seems to have what I'm looking for. Any chance you can explain the SET statement. What exactly are $d$_set & $t$h$h$h Commented Jun 30, 2009 at 16:29
  • 1
    set is a "SET variable" statement. Where the date variable is $d$_ (day + the rest) and time variable is $t$h$h$h (time + ms). I tried to show how it can be done with a set of variables it can work fine without the prompt line. I basicly tried to do this set date=%YYYY%%MM%%DD% but I'm running Linux here and compiling the script on SciTE so I dont know if it works. Sorry if it doesn't work.
    – Secko
    Commented Jun 30, 2009 at 17:00
  • Forgot to add, $_ is newline.
    – Secko
    Commented Jun 30, 2009 at 17:15
  • 1
    Also try, @prompt //$d$_ $t$h$h$h$h$h$h//
    – Secko
    Commented Jun 30, 2009 at 17:22
  • Note that this is also not locale-independent. The date is formatted to the current culture setting, in my case DD.MM.YYYY (for German).
    – djk
    Commented Jun 8, 2016 at 13:39
2

I put together a little C program to print out the current timestamp (locale-safe, no bad characters...). Then, I use the FOR command to save the result in an environment variable:

:: Get the timestamp
for /f %%x in ('@timestamp') do set TIMESTAMP=%%x

:: Use it to generate a filename
for /r %%x in (.\processed\*) do move "%%~x" ".\archived\%%~nx-%TIMESTAMP%%%~xx"

Here's a link:

https://github.com/HarryPehkonen/dos-timestamp

2

I know this thread is old but I just want to add this here because it helped me alot trying to figure this all out and its clean. The nice thing about this is you could put it in a loop for a batch file that's always running. Server up-time log or something. That's what I use it for anyways. I hope this helps someone someday.

@setlocal enableextensions enabledelayedexpansion
@echo off

call :timestamp freshtime freshdate
echo %freshdate% - %freshtime% - Some data >> "%freshdate - Somelog.log"

:timestamp
set hour=%time:~0,2%
if "%hour:~0,1%" == " " set hour=0%hour:~1,1%
set min=%time:~3,2%
if "%min:~0,1%" == " " set min=0%min:~1,1%
set secs=%time:~6,2%
if "%secs:~0,1%" == " " set secs=0%secs:~1,1%
set FreshTime=%hour%:%min%:%secs%

set year=%date:~-4%
set month=%date:~4,2%
if "%month:~0,1%" == " " set month=0%month:~1,1%
set day=%date:~7,2%
if "%day:~0,1%" == " " set day=0%day:~1,1%
set FreshDate=%month%.%day%.%year%
1
  • This was useful for me, although in a ".cmd" file, the colons in the "FreshTime" variable caused errors when used for a file name in my "robocopy" cmdline: ERROR : Invalid Parameter #12 : "/LOG:C:\opt\Sync_08.10.2020_16:27:39.log" As a fix I used dashes instead: set FreshTime=%hour%-%min%-%secs%
    – netDesign8
    Commented Aug 10, 2020 at 20:56
2

You can simply detect the current local format and can get the date in your format, for example:

::for 30.10.2016 dd.MM.yyyy
if %date:~2,1%==. set d=%date:~-4%%date:~3,2%%date:~,2%
::for 10/30/2016 MM/dd/yyyy
if %date:~2,1%==/ set d=%date:~-4%%date:~,2%%date:~3,2%
::for 2016-10-30 yyyy-MM-dd
if %date:~4,1%==- set d=%date:~,4%%date:~5,2%%date:~-2%
::variable %d% have now value: 2016103 (yyyyMMdd)
set t=%time::=%
set t=%t:,=%
::variable %t% have now time without delimiters
cp source.log %d%_%t%.log
2

I know this is an old post, but there is a FAR simpler answer (though maybe it only works in newer versions of windows). Just use the /t parameter for the DATE and TIME dos commands to only show the date or time and not prompt you to set it, like this:

@echo off
echo Starting test batch file > testlog.txt
date /t >> testlog.txt
time /t >> testlog.txt
1

1) You can download GNU coreutils which comes with GNU date

2) you can use VBScript, which makes date manipulation easier in Windows:

Set objFS = CreateObject("Scripting.FileSystemObject")
strFolder = "c:\test"
Set objFolder = objFS.GetFolder(strFolder)
current = Now
mth = Month(current)
d = Day(current)
yr = Year(current)
If Len(mth) <2 Then
    mth="0"&mth
End If
If Len(d) < 2 Then
    d = "0"&d
End If
timestamp=yr & "-" & mth &"-"& d
For Each strFile In objFolder.Files
    strFileName = strFile.Name
    If InStr(strFileName,"file_name_here") > 0 Then
        BaseName = objFS.GetBaseName(strFileName)
        Extension = objFS.GetExtensionName(strFileName)
        NewName = BaseName & "-" & timestamp & "." & Extension
        strFile.Name = NewName
    End If
Next

Run the script as:

c:\test> cscript /nologo myscript.vbs
1

This is a 12 year old thread, but still active, and there has not yet been a truly locale-independent batch-only solution so here's my tuppence.

This should work on any windows setup, regardless of your local date settings. To be sure you get the correct DD MM and YYYY parts of the date you need to change the registry short-date format. Try this:

  • Store current registry short-date format in a local variable
  • Set the registry format to YYYYMMDD (or whatever you want)
  • Store current date to a local variable
  • Reset registry back to the original format

I keep the script below in 'YYYYMMDD.bat' and call it as needed.

@echo off 
:: Create environment variable containing current date in YYYYMMDD format.
:: Intended to be called from other batch jobs

::Save current registry date format
for /f "tokens=2*" %%a in ('reg query "HKCU\Control Panel\International" /v sShortDate^|find "REG_SZ"') do set "ssShortDate=%%b"

::Change registry date format to yyyymmdd 
reg add "HKCU\Control Panel\International" /f /v sShortDate /d "yyyyMMdd" >nul

::Save current date in yyyymmdd format 
set "YYYYMMDD=%date%"

::Restore original format to registry
reg add "HKCU\Control Panel\International" /f /v sShortDate /d "%ssShortDate%" >nul

echo YYYYMMDD=%YYYYMMDD%
timeout /t:1 >nul
exit /b
0

This works well with (my) German locale, should be possible to adjust it to your needs...

forfiles /p *PATH* /m *filepattern* /c "cmd /c ren @file 
%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%_@file"
1
  • 1
    %DATE:~6,4%%DATE:~3,2%%DATE:~0,2% works for portuguese location too! I mean YYYYMMDD Commented Aug 13, 2020 at 14:41
0

For big zip files for deployment, I use quarter hours. No one else on this page had mentioned it before, so I'll put my small script here:

set /a "quarter_hours=%time:~0,2%*4 + %time:~3,2% / 15"
set "zip_file=release_%DATE:~-4%.%DATE:~4,2%.%DATE:~7,2%.%quarter_hours%.zip"

It doesn't zero pad quarter hours from midnight to 5am yet, but it still makes it so you can have a stamped release multiple times a day with few collisions.

Hope that helps.

0

used Martin's suggestion with a little tweak to add time stamp to the file name:

forfiles /p [foldername] /m rsync2.log /c "cmd /c ren @file %DATE:~6,4%%DATE:~3,2%%DATE:~0,2%_%time:~-11,2%-%time:~-8,2%-%time:~-5,2%-@file

For the 10:17:21 23/10/2019 The result is:

20191023_10-17-21-rsync2.log

0
            echo Date and Time: %date% %time%
            rem 29/09/2021 10:01:34,23

            set timestamp=%time: =0%
            set timestamp=%timestamp::=%
            set timestamp=%timestamp:,=%
            set timestamp=%date:/=%%timestamp%

            echo Timestamp (ddMMYYYYHHmmssms): %timestamp%
            rem 2909202109543118

            set timestamp=%timestamp:~4,4%%timestamp:~2,2%%timestamp:~0,2%%timestamp:~8,8%
            echo Timestamp (YYYYMMddHHmmssms) %timestamp%
            rem 2021092910013423
-1

Notice that you could be a little bit more flexible by using negative indexes... It will fit both English and West Europe date formats (of course with switched positions between days and months)

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

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