# Can (La)TeX compare the time stamps of two external files?

## Scenario

I have a bunch of standalone PSTricks files. Each of those files can be compiled by latex-dvips-ps2pdf-pdfcrop-pdftops to produce a PDF image. I have made a batch file to do latex-dvips-ps2pdf-pdfcrop-pdftops.

In my main input file, I will iterate through the PSTricks files. For each iteration, I check whether or not the corresponding PDF exists. If the corresponding PDF already exists, I check whether or not its time stamp is newer than that of its .tex file. Otherwise I will invoke \immediate\write18 mybatch.bat filename.tex to produce or re-produce the corresponding PDF file.

## Question

Can (La)TeX compare the time stamps of two external files? Providing the complete working source code for my scenario above is preferred. :-)

Note: Actually I can make an external script to iterate through the PSTricks files and invoke this script only once from within the main input file. But I am interested in creating the hybrid solution.

-

I wrote the filemod package just for this task which I also need for the upcoming version of standalone. It requires pdf(La)TeX or Lua(La)TeX but doesn't work with Xe(La)TeX.

Basic Usage:

\Filemodcmp{<file 1>}{<file 2>}{<1 is newer>}{<2 is newer>}


There is also a fully expandable version called \filemodcmp and also macros to find the newest or oldest file from a given list.

-
Does it work with latex? –  xport Jun 16 '11 at 0:52
This seems very useful. Is this going to make it into the upcoming TexLive 2011 release in July? –  Peter Grill Jun 16 '11 at 2:40
@xport: It works with LaTeX and plainTeX, that's why I wrote (La)TeX. –  Martin Scharrer Jun 16 '11 at 6:48
@Peter: It is already in TeXLive 2010. TeXLive normally adds new CTAN packages within a week, except if it is frozen, which is the case now. However, the package is already out for a few month. Of course, if you talk about pre-packed and never updated versions of TeXLive like the one which comes with Ubuntu than you will need to wait for TL 2011. –  Martin Scharrer Jun 16 '11 at 6:53
\def\comparetimestamp#1#2{%
\ifnum\pdfstrcmp{\pdffilemoddate{#1}}{\pdffilemoddate{#2}}<0
\message{#1 is older than #2}%
\fi}


Change the \message line to what you need. Not usable with XeLaTeX, only with (pdf)latex. It may give problems if there's a change in the time zone (for example when changing to or from DST) between runs, but this should not be a problem.

-
Very nice idea to use \pdfstrcmp for the comparison. I actually parsed the \pdffilemoddate to a date and time integer value which I compared in two steps... –  Martin Scharrer Jun 15 '11 at 23:25
@Martin: It has the same drawback as parsing the date, when the time zone changes, say from +01'00' to +02'00'. –  egreg Jun 16 '11 at 8:29
I know, but in one compiler run the same time zone for all files should be returned, shouldn't it? –  Martin Scharrer Jun 16 '11 at 9:14
@Martin: not when the Daylight Saving Time starts or ends. That's twice a year, and only in one occasion the clock goes back. Not really a problem, I believe: the change happens when people usually are sleeping. –  egreg Jun 16 '11 at 9:26

You could use luatex. ConTeXt wrapper mtxrun provides one such implementation based on timestamps

mtxrun --iftouched=file.tex,file.pdf --direct pdflatex file


and one based on md5 sum

mtxrun --ifchanged=file.tex --direct pdflatex file


which creates a md5 sum for file.tex and run the command only if the md5 sum has changed. See the source code of mtxrun.lua for implementation. The relevant functions are:

function file.needs_updating(oldname,newname,threshold) -- size modification access change
local oldtime = lfs.attributes(oldname, modification)
local newtime = lfs.attributes(newname, modification)
if newtime >= oldtime then
return false
elseif oldtime - newtime < (threshold or 1) then
return false
else
return true
end
end

function file.checksum(name)
if md5 then
if data then
return md5.HEX(data)
end
end
return nil
end

if md5 then
local data = io.loaddata(name .. ".md5")
return data and (gsub(data,"%s",""))
end
return nil
end


Rest is just a matter of wrapping them around user macros.

-
+1 for informing this capability in ConTeXt. But I am not using it now. Maybe someday. –  xport Jun 15 '11 at 22:10
ConTeXt can make use of LuaTeX? –  xport Jun 15 '11 at 22:11
@xport: you don't need to use ConTeXt to use this feature. As the example shows, you can run pdflatex using mtxrun. (There is a bug in the implementation of --iftouched, so only --ifchanged will work. –  Aditya Jun 15 '11 at 22:12
@xport: ConTeXt is using LuaTeX (rather texlua symlink to luatex binary). I added the relevant lua code. –  Aditya Jun 15 '11 at 22:13

This answer will have nothing to do with TeX, but I would like to point out that using the right tools greatly simplifies the solution. In this case, you should use make. There is a good manual on this tool here.

A very simple Makefile follows (it should be expanded further to fit good practices):

TARGETS = <list of targets to build> (GNU Make's wildcard and patsubst might help)

.PHONY: all clean

all: $(TARGETS) %.pdf: %.tex <call your batch file or directly integrate commands here,$< stands for source name>

clean:
$(RM)$(TARGETS)


Now just type make at any time and it will ensure the targets are up to date.

-
Yes. It is clearly preferable to use the right tool for the job. However, make isn't particularly good for using with latex, due to the need to rerun latex multiple times (with makeindex, bibtex, etc) interspersed. It takes quite a lot of effort to convince make to run latex enough times (but not too many). For simple jobs like converting figures, this isn't a problem (in fact I too use make for this myself), but for more sophisticated uses of latex, I would use something like rubber. –  Lev Bishop Jun 16 '11 at 15:49
@Lev: It is not so hard. In my Makefiles I re-run LaTeX if any of the auxiliary files like .aux or .toc has changed. To do so, I compare the checksums of these files, which I keep in a separate file, before and after a LaTeX run. The list of auxiliary files can be obtained from the .log file (look for \openout lines). The workflow is then as follows: 1. Run LaTeX; 2. While (the checksum file is missing) OR (not all checksums match) Do { Obtain the list of auxiliary files; Compute and store new checksums; Run additional commands like MakeIndex; Run LaTeX }. –  Andrey Vihrov Jul 23 '11 at 14:08
Sure, you can do it that way. But then you are not getting much benefit from using make and you may as well have written the logic you described using some proper scripting language (perl, python, etc) or rather than reinvent the wheel just stick with one of the preexisting solutions such as rubber or latexmk. –  Lev Bishop Jul 23 '11 at 19:19