1

I am trying to get the Date and Time (on a variable) of the most recently modified file in the Logs folder but I always get an error ('was unexpected at this time.')

I am using the following code:

@echo off
SETLOCAL

for /f %%G in ('dir .\Logs /b/a-d/o-d/t:w') do (
    if not defined NewestFileTime (
        set NewestFileTime=%%~tG
    ) else (
        if %NewestFileTime% GTR %%~tG set NewestFileTime=%%~tG
    )
)

if not defined NewestFileTime (
    echo There is no file in current directory.
    goto :exit
)

echo Last file modification time is: %NewestFileTime%

:exit
endlocal
echo.
echo Press CTRL+C to exit
pause
T3RR0R
  • 2,747
  • 3
  • 10
  • 25
pdpereira
  • 11
  • 3
  • The 1st thing that sticks out is Trying to Do a Numerical Comparison On `%%~tG`, which expands to a String. Look here for Some Ideas about turning the Value of `%%~tG` into a Useful form for comparison. `https://pastebin.com/F4yUs8Bq` – T3RR0R Feb 04 '20 at 18:10
  • You'll essentially need to break down the value of %%~tG into the Seperate Date and Time Components, Then Convert those into Forms Useful For Numerical Comparison – T3RR0R Feb 04 '20 at 18:34
  • Given the format of `YYYY-MM-DD hh:mm am|pm` a string comparison should be equivalent to a numerical comparison. `"2016-10-18 04:37 PM" gtr "2016-10-18 04:37 AM"` is true, provided the strings are both in quotes. – jwdonahue Feb 04 '20 at 18:47
  • You've got a [delayed expansion issue](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected/30284028#30284028). Besides that, you may get unexpected results with files >2GB (due to the INT32 limitation of `cmd`) – Stephan Feb 04 '20 at 19:05
  • If you don’t need get this in all files an to compute the difference between one to another file, let me know, and I’ll port the code to do with 1st/one (listed by dir)... sorry my limited English... – Io-oI Feb 11 '20 at 22:22

2 Answers2

1

You have a complex of overlapping bugs in your script:

  • You need to have delayed expansion enabled, due to the code blocks.
  • You used the wrong operator in your comparison.
  • You must quote the strings in the comparison.

One thing you should always be aware of, when comparing strings, particularly those that represent numbers, is the comparison is based on the code points of your configured language. So "2019-1-1" < "2019-01-01" due to the the different lengths of the strings. But it is okay to compare date/time strings that use the same format, if and only if they adhere to the full YYYY-MM-DD and hh:mm am|pm formats.

Here's your fixed up code:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

for /f %%G in ('dir .\Logs /b/a-d/o-d/t:w') do (
    if not defined NewestFileTime (
        set NewestFileTime=%%~tG
    ) else (
        if "!NewestFileTime!" LSS "%%~tG" set NewestFileTime=%%~tG
    )
)

if not defined NewestFileTime (
    echo There is no file in current directory.
    goto :exit
)

echo Last file modification time is: %NewestFileTime%

:exit
endlocal
echo.
echo Press CTRL+C to exit
pause

Tested against this directory on my system:

Directory of D:\TMP\test\Logs

2020-02-04  11:37 AM    <DIR>          .
2020-02-04  11:37 AM    <DIR>          ..
2020-01-16  02:07 AM               135 fqpnTest.cmd
2020-02-04  11:32 AM               578 test.cmd
2020-02-04  11:37 AM                15 test.txt
               3 File(s)            728 bytes

Results are:

> test
Last file modification time is: 2020-02-04 11:40 AM

Press CTRL+C to exit
Press any key to continue . . .

The apparent time discrepancy is caused by the fact that my creation times aren't equal to my last update times.

jwdonahue
  • 6,199
  • 2
  • 21
  • 43
  • Well it was a step further. At least it now shows this output: Last file modification time is: But I can't see the value %%~tG – pdpereira Feb 04 '20 at 19:02
  • Yup, I always try to avoid using parens in my script. As Stephan pointed out in a comment to your OP, you have a delayed expansion issue. I'll update accordingly... – jwdonahue Feb 04 '20 at 19:16
  • As stated in my previous comment, GTR EQU LSS type comparisons are Numerical Comparisons within batch, And are not correct for usage in String comparisons - Results using this form of Comparison on strings will fail far more often than Not. – T3RR0R Feb 04 '20 at 19:16
  • @T3RR0R, your statement isn't accurate. Can there be problems? Sure, but as long as you're comparing apples to apples, you're fine. String comparisons are used in scripts all the time to do sorting. One just has be be aware of the sort order. In this case, the data/timestamps have a fixed format that should always yield the same results as if you had done a full numeric conversion. – jwdonahue Feb 04 '20 at 19:59
  • @jwdonahue: I have tried your code but it doesn't work. I added the code line: echo NewestFileTime:%NewestFileTime% just before the else statement and I am getting the following output: NewestFileTime: NewestFileTime: NewestFileTime: NewestFileTime: NewestFileTime: There is no file in current directory. Press CTRL+C to exit Press any key to continue . . . – pdpereira Feb 05 '20 at 18:33
  • My ultimate goal is to determine if the date of the last modified file is at least 3h ago (comparing to the current time). If it is my script will continue, otherwise it finishes. – pdpereira Feb 06 '20 at 11:04
  • @pdpereira, well that is a detail you should add to your question above. The code works fine, provided there is a `Logs` directory in the current directory and it has files in it. The time format returned by `%DATE%` and `%TIME%` is not always the same as that which is returned by the file system with `%~t` substitution syntax. – jwdonahue Feb 06 '20 at 17:32
0

For a single file and also get date/time of the first outputs of the commands below in the loop for:

dir .\*.log /b /a:-d /o-d /t:w 
%__APPDIR__%wbem\wmic.exe datafile where name="G:\\some_folder\\file_.ext" get "LastModified"


@echo off && setlocal enabledelayedexpansion

cd /d "%~dp0" & cls & echo/ && title <nul && title ...\%~nx0 

for /f "tokens=* delims= " %%i in ('dir .\*.log /b /a:-d /o-d /t:w')do set "_F=%%~fi" && for /f ^tokens^=^1^ ^delims^=^+^. %%d in ('
%__APPDIR__%wbem\wmic.exe datafile where name^="!_F:\=\\!" get "LastModified"^|%__APPDIR__%findstr.exe [0-9]')do set "_d=%%~d" && (
call set "_d=!_d:~0,14!" && call set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~12,2!" && set "_nft=%%~xni"
goto :next )

:next
echo/ && for /f "tokens=1-3*delims= " %%i in ('echo[!_ft!')do set "_f=%%~i" && set "_df=%%~j" && set "_~t=%%~ti" && set "_t=%%~k"
echo/ File Name: !_f! && echo/ File Date: !_df! & echo/ File Time: !_~t! & echo/ Date and Time for the variable %%%%~ti is: !_~t!
call echo/ Name !_f! Date !_df! Time !_t! & echo/ WMIC Last Modified is: !_d! & %__APPDIR__%timeout.exe -1 & endlocal & goto :EOF

  • Same code in conventional formatting:
@echo off && setlocal enabledelayedexpansion

cd /d "%~dp0"
cls
echo/
title <nul
title ...\%~nx0 

for /f "tokens=* delims= " %%i in ('dir .\*.log /b /a:-d /o-d /t:w')do (
   set "_F=%%~fi"
   for /f "tokens=1 delims=+." %%d in (
      '%__APPDIR__%wbem\wmic.exe datafile where name^="!_F:\=\\!" get "LastModified"^|%__APPDIR__%findstr.exe [0-9]'
         ) do ( 
           set "_d=%%~d" && (
            call set "_d=!_d:~0,14!"
            call set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~12,2!"
            set "_nft=%%~xni"
            goto :next
           )
         )
      )

:next
echo/
for /f "tokens=1-3*delims= " %%i in ('echo[!_ft!')do (
    set "_f=%%~i"
    set "_df=%%~j"
    set "_~t=%%~ti"
    set "_t=%%~k"
    )

echo/ File Name: !_f!
echo/ File Date: !_df!
echo/ File Time: !_~t!
echo/ Date and Time for the variable %%%%~ti is: !_~t!
call echo/ Name !_f! Date !_df! Time !_t!
echo/ WMIC Last Modified is: !_d!

%__APPDIR__%timeout.exe -1
endlocal
goto :EOF

 File Name: Q60062965.LOG
 File Date: 2020/02/12
 File Time: 2020-02-12 12:56 AM
 Date and Time for the variable %%~ti is: 2020-02-12 12:56 AM
 Name Q60062965.LOG Date 2020/02/12 Time 00:56:14
 WMIC Last Modified is: 20200212005614



For multiple files:

  • To get the date/time the file was last modified, try using wmic instead %%~ti in a for variable looping:
%__APPDIR__%wbem\wmic.exe datafile where name="G:\\some_folder\\file_.ext" get "LastModified"


  • To compare dates and get the latest modified file, I am using a date format yyyyMMDDHHmmss.

So, with this layout, I compose a number where the most recent value is always known with the highest numerical value.

To compare the value and get the largest between two dates/numbers with 14 digits, why not help a little with

  • For use/test, just edit: cd /d "%~dp0" to c:\folder\logs
@echo off && setlocal enabledelayedexpansion

cd /d "%~dp0" & cls & echo/
title <nul && title ...\%~nx0 

set "_yep=%temp%\_yep_tmp.vbs"
set "_vbs=%__APPDIR__%cscript.exe"
set "_fstr=%__APPDIR__%findstr.exe"
set "_dir=dir .\*.log  /b /a:-d /o-d /t:w"
set "_wmic=%__APPDIR__%wbem\wmic.exe datafile where name"

>"!_yep!" echo/if int(wsh.Arguments(0^)^)^>=int(wsh.Arguments(1^)^)then wsh.echo "yep"

for /f ^tokens^=^* %%i in ('call !_dir!')do (set "_F=%%~fi" && for /f tokens^=^1^ ^delims^=^+. %%d in (
'!_wmic!^="!_F:\=\\!" get "LastModified" ^|call !_fstr! [0-9]')do (set "_d=%%~d" && if "!_NFT!" == "" (
set "_NFT=!_d:~0,14!" && set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~12,2!"
) else (call !_vbs! "!yep!" !_d:~0,14! !_NFT!|call !_fstr! yep >nul && call set "_NFT=!_d:~0,14!") && (
call set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~14,4!"))& echo/ %%~i !_d!)

echo/ & for /f "tokens=1-3" %%i in ('echo[!_ft!')do (set "_f=%%i" && set "_df=%%~j" && set "_~t=%%~ti"
set "_t=%%~k" && call echo/ File Name: !_f! && call echo/ File Date: !_df! && echo/ File Time: %%~ti )

echo/ & echo/ Date and Time for the variable %%%%~ti is !_~t! && echo/ WMIC.exe command outputs !_NFT!
echo/ Name !_f! Date !_df! Time !_t! && echo/ WMIC Last Modified: !_NFT! && %__APPDIR__%timeout.exe -1
del /q /f "!_yep!" 2>nul >nul & endlocal && goto :EOF

 Q60062965.log 20200211231602
 Q26635801.log 20190801440758
 Q18326477.log 20191821232201

 File Name: Q60062965.log
 File Date: 2020/02/11
 File Time: 2020-02-11 11:16 PM

 Date and Time for the variable %%~ti is 2020-02-11 11:16 PM
 WMIC.exe command outputs 20200211231602
 Name Q60062965.log Date 2020/02/11 Time 23:16:02
 WMIC Last Modified: 20200211231602

  • The code for check date/time >= with no escaping::
if int(wsh.Arguments(0))>=int(wsh.Arguments(1))then wsh.echo "yep"

  • The command line to run/execute file %temp%\_yep_tmp.vbs :
%__APPDIR__%cscript.exe "%temp%\_yep_tmp.vbs" 20200211180712 20200211174953 

  • Outputs file :
yep

  • Same code in conventional formatting
@echo off && setlocal enabledelayedexpansion

cd /d "%~dp0" & cls & echo/
title <nul && title ...\%~nx0 

>"%temp%\_yep_tmp.vbs" echo/if int(wsh.Arguments(0^)^)^>=int(wsh.Arguments(1^)^)then wsh.echo "yep"

for /f "tokens=*" %%i in ('dir .\*.log /b /a:-d /o-d /t:w')do (
   set "_F=%%~fi"
   for /f "tokens=1 delims=+." %%d in (
      '%__APPDIR__%wbem\wmic.exe datafile where name^="!_F:\=\\!" get "LastModified" ^|%__APPDIR__%findstr.exe [0-9]')do (
          set "_d=%%~d" 
          if "!_NFT!" == "" (
             set "_NFT=!_d:~0,14!"
             set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~12,2!"
           ) else (
             %__APPDIR__%cscript.exe "%temp%\_yep_tmp.vbs" !_d:~0,14! !_NFT!|%__APPDIR__%findstr.exe! yep >nul
             call set "_NFT=!_d:~0,14!"
                ) && (
                  call set "_ft=%%~nxi !_d:~0,4!/!_d:~4,2!/!_d:~6,2! !_d:~8,2!:!_d:~10,2!:!_d:~14,4!"
                )
           ) 
      echo/ %%~i !_d!
   )

echo/
for /f "tokens=1-3" %%i in ('echo[!_ft!')do (
   set "_f=%%i"
   set "_df=%%~j"
   set "_~t=%%~ti"
   set "_t=%%~k"
   call echo/ File Name: !_f!
   call echo/ File Date: !_df!
   echo/ File Time: %%~ti
   )

echo/ 
echo/ Date and Time for the variable %%%%~ti is !_~t!
echo/ WMIC.exe command outputs !_NFT!
echo/ Name !_f! Date !_df! Time !_t!
echo/ WMIC Last Modified: !_NFT!

del /q /f "!_yep!" 2>nul >nul
%__APPDIR__%timeout.exe -1
endlocal
goto :EOF

Io-oI
  • 2,514
  • 3
  • 22
  • 29