0

I have found a batch script that calculates the age of files in days and outputs the result to the screen. I am trying to modify this script so that it will determine "the number of days since file modify date" for each file in a folder and output the result to a text file.

I have been fiddling with the script for a few days now and would appreciate if someone could help me out.

Thank you!

Screenshot

@echo off
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION


call:jdate tnow "%date%"
for %%F in (*.*) do (
    call:ftime tfile "%%F"
    set /a diff=tnow-tfile
    echo.%%~nxF is !diff! days old
)

ECHO.&PAUSE&GOTO:EOF


::-----------------------------------------------------------------------------------
::-- Functions start below here
::-----------------------------------------------------------------------------------


:ftime JD filename attr -- returns the file time in julian days
::                      -- JD    [out]    - valref file time in julian days
::                      -- attr  [in,opt] - time field to be used, creation/last-access/last-write, see 'dir /?', i.e. /tc, /ta, /tw, default is /tw
:$created 20060101 :$changed 20090322 :$categories DateAndTime
:$source http://www.dostips.com
SETLOCAL
set file=%~2
set attr=%~3
if not defined attr (call:jdate JD "- %~t2"
) ELSE (for /f %%a in ('"dir %attr% /-c "%file%"|findstr "^^[0-9]""') do call:jdate JD "%%a")
( ENDLOCAL & REM RETURN VALUES
    IF "%~1" NEQ "" (SET %~1=%JD%) ELSE (echo.%JD%)
)
EXIT /b


:jdate JD DateStr -- converts a date string to julian day number with respect to regional date format
::                -- JD      [out,opt] - julian days
::                -- DateStr [in,opt]  - date string, e.g. "03/31/2006" or "Fri 03/31/2006" or "31.3.2006"
:$reference http://groups.google.com/group/alt.msdos.batch.nt/browse_frm/thread/a0c34d593e782e94/50ed3430b6446af8#50ed3430b6446af8
:$created 20060101 :$changed 20080219
:$source http://www.dostips.com
SETLOCAL
set DateStr=%~2&if "%~2"=="" set DateStr=%date%
for /f "skip=1 tokens=2-4 delims=(-)" %%a in ('"echo.|date"') do (
    for /f "tokens=1-3 delims=/.- " %%A in ("%DateStr:* =%") do (
        set %%a=%%A&set %%b=%%B&set %%c=%%C))
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
ENDLOCAL & IF "%~1" NEQ "" (SET %~1=%JD%) ELSE (echo.%JD%)


EXIT /b​
  • You placed numerous wrong spaces everywhere in your code, and you omitted some which are mandatory!! for instance, `for % % F in ( * .*) do(` cannot work, it must read `for %%F in (*.*) do (`... – aschipfl Dec 30 '15 at 12:36
  • Not sure why there were empty spaces in the script window, I have now removed them – user5691708 Dec 30 '15 at 12:53
  • Okay, thanks... and what is your question? please regard that task requests are off-topic on SO... – aschipfl Dec 30 '15 at 13:56
  • Currently, the script outputs the result (e.g. file 1 is XX days old") to the screen. How do I echo it to a log file? – user5691708 Dec 30 '15 at 14:43
  • I believe it should look something like that: e.g. echo !diff! > log.txt – user5691708 Dec 30 '15 at 14:47
  • 1
    You will need `>>` instead of `>` to append rather than overwrite; I would go for `>> log.txt echo.!diff!` to avoid trailing spaces in the log file; or even better: put the entire `for %%F` loop structure into a pair of `()` and place the redirection `> log.txt` after the closing `)`, because this is better in performance... – aschipfl Dec 30 '15 at 15:04
  • I have enclosed "for %%" in parenthesis and echo-ed out the result to a txt file. This seems to have worked: (for %%F in (*.*) do ( call:ftime tfile "%%F" set /a diff=tnow-tfile echo.%%~nxF is !diff! days old) >> temp_log.txt – user5691708 Dec 30 '15 at 17:08
  • The result is as follows: "test1.txt is 149 days old" – user5691708 Dec 30 '15 at 17:11
  • Now I am trying to add "file name", "modify date" & "cretion date" and append "Days since creation": – user5691708 Dec 30 '15 at 17:13
  • ( echo "Name","Modification Time","Creation Time","Days Old" for %%f in (*) do ( set "name=%%~nxf" if not "!name!"=="%~nx0" ( set "mtime=%%~tf" for /f "tokens=1-3" %%d in ( 'dir /t:c "!name!" ^| find /i "!name!"' ) do set "ctime=%%~d %%~e %%~f" echo "!name!","!mtime!","!ctime!",echo.%%~nxF is !diff! days old ) – user5691708 Dec 30 '15 at 17:13
  • In PowerShell your entire script would be `dir | select Name, LastWriteTime,CreationTime, @{N="Days_Since_Change";E={((Get-Date) - $_.LastWriteTime).Days}}, @{N="Days_Since_Creation";E={((Get-Date) - $_.CreationTime).Days}}` and you could add `| Export-CSV filelist.csv -NoTypeInformation` to the end to put it in a file. PowerShell is way better for dates and times (and files) than batch files, and it's built into all recent Windows versions. – TessellatingHeckler Dec 30 '15 at 20:12
  • Thank you, will try it out in PowerShell – user5691708 Dec 31 '15 at 09:12

1 Answers1

0

Here is the batch code to create for all files in current directory except the batch file and the created log file the output in CSV format with the columns:

  1. Name
  2. Modification Time
  3. Creation Time
  4. Days Old

The batch code with additional comments.

@echo off
setlocal
set "LogFile=temp_log.txt"
call :jdate tnow "%date%"
(
    echo "Name","Modification Time","Creation Time","Days Old"
    for %%F in (*) do call :GetDiffTime "%%F"
) >"%LogFile%"

endlocal
goto :EOF

:GetDiffTime
rem Do not add this batch file in log file.
if "%~1" == "%~nx0" goto :EOF

rem Do not add log file in log file.
if "%~1" == "%LogFile%" goto :EOF

rem Determine difference in days of last modification
rem date of current file with current date in days.
call :ftime tfile "%~1"
set /A diff=tnow-tfile

rem Get creation date of current file from output of DIR.

rem The tokens are:

rem    a ... creation date
rem    b ... creation time
rem    c ... file size in bytes
rem    d ... file name without path

for /F "tokens=1-3*" %%a in ('dir /t:c "%~1"') do (
    if "%%d" == "%~1" (
        echo "%~1","%~t1","%%~a %%~b",%diff%
        goto :EOF
    )
)
goto :EOF

::-----------------------------------------------------------------------------------
::-- Functions start below here
::-----------------------------------------------------------------------------------


:ftime JD filename attr -- returns the file time in julian days
::                      -- JD    [out]    - valref file time in julian days
::                      -- attr  [in,opt] - time field to be used, creation/last-access/last-write, see 'dir /?', i.e. /tc, /ta, /tw, default is /tw
:$created 20060101 :$changed 20090322 :$categories DateAndTime
:$source http://www.dostips.com
SETLOCAL
set file=%~2
set attr=%~3
if not defined attr (
    call :jdate JD "- %~t2"
) ELSE (
    for /f %%a in ('"dir %attr% /-c "%file%"|findstr "^^[0-9]""') do call :jdate JD "%%a"
)
( ENDLOCAL & REM RETURN VALUES
    IF "%~1" NEQ "" (SET %~1=%JD%) ELSE (echo.%JD%)
)
EXIT /b


:jdate JD DateStr -- converts a date string to julian day number with respect to regional date format
::                -- JD      [out,opt] - julian days
::                -- DateStr [in,opt]  - date string, e.g. "03/31/2006" or "Fri 03/31/2006" or "31.3.2006"
:$reference http://groups.google.com/group/alt.msdos.batch.nt/browse_frm/thread/a0c34d593e782e94/50ed3430b6446af8#50ed3430b6446af8
:$created 20060101 :$changed 20080219
:$source http://www.dostips.com
SETLOCAL
set DateStr=%~2&if "%~2"=="" set DateStr=%date%
for /f "skip=1 tokens=2-4 delims=(-)" %%a in ('"echo.|date"') do (
    for /f "tokens=1-3 delims=/.- " %%A in ("%DateStr:* =%") do (
        set %%a=%%A&set %%b=%%B&set %%c=%%C
    )
)
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"

rem For German Windows comment line above and uncomment line below.
rem set /a "yy=10000%JJ% %%10000,mm=100%MM% %% 100,dd=100%TT% %% 100"

set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
ENDLOCAL & IF "%~1" NEQ "" (SET %~1=%JD%) ELSE (echo.%JD%)

EXIT /b

Note:

Function jdate is designed for dates like 12/30/2015 or Wed 12/30/2015 or 30.12.2015, but does nevertheless not work for German Windows as output of command date is not dd-mm-yy as expected by code. Command date outputs on German Windows TT-MM-JJ as date format mask. Users of German Windows should read the two rem lines near end of batch script added by me.

Example:

Command DIR executed in directory C:\Temp outputs on German Windows:

15.08.2015  22:01             2.286 about.txt
27.12.2014  21:28             8.871 help for.txt
15.03.2015  17:41             2.372 RegJump.bat
04.01.2016  12:24             2.937 Test.bat
10.11.2015  17:44         9.003.869 TV Manual.pdf

Running Test.bat on German Windows with the code above adapted to German Windows results in file C:\Temp\temp_log.txt with contents:

"Name","Modification Time","Creation Time","Days Old"
"about.txt","15.08.2015 22:01","04.01.2016 12:30",142
"help for.txt","27.12.2014 21:28","27.12.2014 21:28",373
"RegJump.bat","15.03.2015 17:41","15.03.2015 15:23",295
"TV Manual.pdf","10.11.2015 17:44","10.11.2015 17:40",55

File about.txt has a creation date newer than last modification date because just copied to directory C:\Temp for testing the batch file and therefore creation date was the current date on making this copy.


Here is an enhanced version of batch code above with following differences:

  1. Produces correct output even with @echo on in first line or without turning off command output.
  2. Runs recursive for all files in current directory and all subdirectories. The output file contains each file name with full path. Remove /R in line 6 to process only files in current directory.
  3. Works also for file and folder names containing characters with special meaning in batch processing like folder name HLA Compiler (masm32+) which contains an opening and a closing parenthesis.

This batch file writes the file names always with full path into the output file even on running on current directory only. But this can be changed in echo line in subroutine GetDiffTime by using for example %~nx1 instead of %~1 which required improvements in subroutine ftime.

@echo off
setlocal
set "LogFile=%CD%\temp_log.txt"
call :jdate tnow "%date%"
echo "Name","Modification Time","Creation Time","Days Old">"%LogFile%"
for /R %%F in (*) do call :GetDiffTime "%%~fF"
endlocal
goto :EOF

:GetDiffTime
rem Do not add this batch file in log file.
if "%~1" == "%~f0" goto :EOF

rem Do not add log file in log file.
if /I "%~1" == "%LogFile%" goto :EOF

rem Determine difference in days of last modification
rem date of current file with current date in days.
call :ftime tfile "%~1"
set /A diff=tnow-tfile

rem Get creation date of current file from output of DIR.

rem The tokens are:

rem    a ... creation date
rem    b ... creation time
rem    c ... file size in bytes
rem    d ... file name without path

for /F "tokens=1-3*" %%a in ('dir /t:c "%~1"') do (
    if "%%d" == "%~nx1" (
        >>"%LogFile%" echo "%~1","%~t1","%%~a %%~b",%diff%
        goto :EOF
    )
)
goto :EOF

::-----------------------------------------------------------------------------------
::-- Functions start below here
::-----------------------------------------------------------------------------------


:ftime JD filename attr -- returns the file time in julian days
::                      -- JD    [out]    - valref file time in julian days
::                      -- attr  [in,opt] - time field to be used, creation/last-access/last-write, see 'dir /?', i.e. /tc, /ta, /tw, default is /tw
:$created 20060101 :$changed 20090322 :$categories DateAndTime
:$source http://www.dostips.com
SETLOCAL EnableDelayedExpansion
set "file=%~2"
set "attr=%~3"
if not defined attr (
    call :jdate JD "- %~t2"
) ELSE (
    for /f %%a in ('"dir %attr% /-c "!file!"|findstr "^^[0-9]""') do call :jdate JD "%%a"
)
( ENDLOCAL & REM RETURN VALUES
    IF "%~1" NEQ "" (SET "%~1=%JD%") ELSE (echo.%JD%)
)
EXIT /b


:jdate JD DateStr -- converts a date string to julian day number with respect to regional date format
::                -- JD      [out,opt] - julian days
::                -- DateStr [in,opt]  - date string, e.g. "03/31/2006" or "Fri 03/31/2006" or "31.3.2006"
:$reference http://groups.google.com/group/alt.msdos.batch.nt/browse_frm/thread/a0c34d593e782e94/50ed3430b6446af8#50ed3430b6446af8
:$created 20060101 :$changed 20080219
:$source http://www.dostips.com
SETLOCAL
set "DateStr=%~2" & if "%~2"=="" set "DateStr=%date%"
for /f "skip=1 tokens=2-4 delims=(-)" %%a in ('"echo.|date"') do (
    for /f "tokens=1-3 delims=/.- " %%A in ("%DateStr:* =%") do (
        set "%%a=%%A" & set "%%b=%%B" & set "%%c=%%C"
    )
)
set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"

rem For German Windows comment line above and uncomment line below.
rem set /a "yy=10000%JJ% %%10000,mm=100%MM% %% 100,dd=100%TT% %% 100"

set /a JD=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
ENDLOCAL & IF "%~1" NEQ "" (SET %~1=%JD%) ELSE (echo.%JD%)

EXIT /b
Mofi
  • 46,139
  • 17
  • 80
  • 143
  • One last question. Could the script be tweaked to traverse subfolders? Currently it only reads the files that are in the same folder as the batch file. – user5691708 Jan 04 '16 at 12:44
  • I updated second batch code to process recursively all files in current directory and all subdirectories, improved subfunctions `ftime` to work also on unusual file and folder names, and beautified `jdate` a little bit. – Mofi Jan 04 '16 at 13:45
  • Hi Mofi! Could you suggest an easy way to sort column "Days Old" in reverse order and output only the values (in "Days Old") that are greater than a specific number (say 30)? I tried incorporating a "sort" command into the script but it did not work. I think I need something like "if %%a GEQ 30" but not sure where to add it. Would greatly appreciate your help. Thank you – user5691708 Jan 15 '16 at 11:21
  • Insert below line with `set /A diff=tnow-tfile` a line with `if %diff% LEQ 30 goto :EOF` to ignore files not older than 30 days. – Mofi Jan 16 '16 at 15:17
  • Please create a new question for sorting the lines in the CSV file from ? to ? based on values in data column ? and explaining sort task. And add to the question also links to [this question](http://stackoverflow.com/questions/34529014/) here and to [How to sort lines of a text file containing version numbers in format major.minor.build.revision numerical?](http://stackoverflow.com/questions/34417346/) It would be possible to sort the file after creation by above batch code, or even better, sort the lines in memory before writing them to file using a numeric sort. – Mofi Jan 16 '16 at 15:30
  • Hey Mofi! Thanks a million. I have now created a new question to address the sorting issue: http://stackoverflow.com/questions/34875448/how-to-sort-lines-in-the-batch-output-log-file-based-on-values-in-one-of-the-col/34875767#34875767 – user5691708 Jan 19 '16 at 11:36