KaiserKatze
KaiserKatze

Reputation: 1569

How to retrieve and change last modification time-stamp of a file on Windows?

I need to implement the same function on both Windows and Linux.

The Linux part is done like this:

#!/bin/sh

path_mainfunctions="../../data/scripts/mainfunctions.lua"
path_DisplayError="scripts/DisplayError.lua"
path_backup="scripts/mainfunctions.lua"

if [ -f $path_backup ]; then
    # check if $path_mainfunctions is newer
    alias stat='stat --format=%Y'
    # retrieve Last-Modified Timestamp of mainfunctions.lua
    lmt_mainfunctions=`stat $path_mainfunctions`
    # retrieve Last-Modified Timestamp of backup file
    lmt_backup=`stat $path_backup`
    if [ $lmt_mainfunctions -gt $lmt_backup ]; then
        # mainfunctions.lua is newer
        # backup, append and touch
        cp $path_mainfunctions $path_backup
        cat $path_DisplayError >> $path_mainfunctions
        touch $path_backup
    fi
else
    # backup
    cp $path_mainfunctions $path_backup

    # append DisplayError.lua to mainfunctions.lua
    cat $path_DisplayError >> $path_mainfunctions

    # touch $path_backup to make it newer than
    # modified file $path_mainfunctions
    touch $path_backup
fi

The Windows part however troublesome:

@ECHO off
SET path_mainfunctions="..\..\data\scripts\mainfunctions.lua"
SET path_DisplayError="scripts\DisplayError.lua"
SET path_backup="scripts\mainfunctions.lua"

@ECHO on
:: if it is the first time you install this mod
:: the mod should backup 'mainfunctions.lua'
:: automatically.
::
:: when the game is updated, the mod should
:: be able to detect such update:
::  -   if %path_mainfunctions% is newer than
::      %path_backup%, the mod will install itself
:: 
::  -   otherwise the mod will touch %path_backup%
IF EXIST %path_backup% (
    :: check if %path_mainfunctions% is newer
    ECHO f | XCOPY /d %path_mainfunctions% %path_backup%

    :: TODO How to get last modified timestamp more easily?
    :: SET DATE_MF=FORFILES %path_mainfunctions% /C "cmd /c ECHO @fdate"
    :: SET DATE_BK=FORFILES %path_backup% /C "cmd /c ECHO @fdate"
    ::
    :: TODO which date format will FORFILES command output?
    :: -    DD/MM/YYYY
    :: -    MM/DD/YYYY
    :: -    YYYY/MM/DD
    ::
    :: split the string and do math to get timestamp
    :: NOTE:
    :: -    SET /A RESULT = %VAR_A% * %VAR_B%
    ::
    :: SET TIME_MF=FORFILES %path_mainfunctions% /C "cmd /c ECHO @ftime"
    :: SET TIME_BK=FORFILES %path_backup% /C "cmd /c ECHO @ftime"
    ::
    :: TODO compare last-modified time-stamp and do something
) ELSE (
    :: Backup mainfunctions.lua
    ECHO f | XCOPY %path_mainfunctions% %path_backup%

    :: Append DisplayError.lua to mainfunctions.lua
    TYPE %path_DisplayError% >> %path_mainfunctions%

    :: touch %path_backup% to make it newer than
    :: modified file %path_mainfunctions%
    :: TODO how to touch a file in Windows ????
)

The problem is that I don't know how to RETRIEVE and CHANGE last modified time-stamp of a file on Windows, just in case you forget my title :)

If you know how to solve the problem with VBScript, I want to know how it is implemented step by step, thanks :)

Upvotes: 0

Views: 1161

Answers (1)

dbenham
dbenham

Reputation: 130819

Here I will present a pure batch solution.

Performing a touch is simple, though totally non-intuitive.

copy /b "somepath\file.ext"+,, "somepath\file.ext" >nul

Comparing file timestamps can be done, but it is inordinately complicated. You can use WMIC to get the last modified timestamp down to fractional seconds. The timestamp is formatted in a way that almost makes a string comparison almost equivalent to a chronological comparison. The problem is the timestamp includes the timezone offset expressed as minutes difference from UTC (GMT). So there is an hour each year during change-over from daylight savings to standard time when the simple string comparison provides the wrong answer. You can also get the wrong answer if the timezone was changed on the computer. It is possible to compensate, but there is a much simpler solution :-)

Determining the newest file is simple if the files are all in the same folder. Simply copy the data file (preserving timestamps) into the same folder as the update file. Then you can use the DIR command to list the files in chronological order, and the last one listed will be the newest!

Putting it all together, I get:

@echo off
setlocal

:: Setup
set "dataPath=..\..\data\scripts"
set "updatePath=scripts"
set "data=mainfunctions.lua"
set "update=DisplayError.lua"

:: Make copy of original for use in date comparison and backup creation
copy /y "%dataPath%\%data%" "%updatePath%\%data%.compare" >nul

:: If this is the first install, then goto :update
if not exist "%updatePath%\%data%" goto update

:: List the update and compare files in chronological order
:: The last one listed will be the newest.
for /f "delims=" %%F in (
  'dir /b /od "%updatePath%\%data%.compare" "%updatePath%\%update%"'
) do set "newest=%%F"

:: If newest equals update then goto :update
if "%newest%" equ "%update%" goto update

:: Nothing to do, so cleanup and exit
del "%updatePath%\%data%.compare"
exit /b

:update
:: Perform the update
type "%updatePath%\%update%" >> "%dataPath%\%data%"

:: Create the backup (also effectively "removes" the compare file)
move /y "%updatePath%\%data%.compare" "%updatePath%\%data%" >nul

:: "touch" the backup to give it a last-modified date greater than the update
copy /b "%updatePath%\%data%"+,, "%updatePath%\%data%" >nul

exit /b

Upvotes: 2

Related Questions