2

What already works

I am using \immediate\write18 to let the GNU date command do some date/time arithmetic. The resulting timestamp in ISO format (e.g., 2011-09-09T09:59:59Z) is written to a temporary file /tmp/date.txt, whose content is then read into the macro \ScriptResult, which I can happily print. So far so good.

What doesn't work yet

I am then trying to use \DTMsavetimestamp from the datetime2 package to save \ScriptResult to a timestamp that I can print via \DTMusedate and \DTMusetime (both also part of datetime2). However, this breaks compilation.

I have absolutely zero doubts that this is due to some expansion-related problem. :)

Minimal (non-)working example

Save the following file to test.tex and try to compile via pdflatex -shell-escape test.tex (-shell-escape crucial due to \write18). Compilation will fail. You can then try to comment the line \DTMsavetimestamp{mytimestamp}{\ScriptResult} and uncomment the line \DTMsavetimestamp{mytimestamp}{2011-09-09T09:59:59Z}, after which the MWE compiles fine. This is what makes me think that this issue relates to expansion.

% NOTE: Compile via: pdflatex -shell-escape

\documentclass{article}

\usepackage{datetime2}

\begin{document}

\def\mydate{2015-01-01}%
\def\mytime{12:23}%
\def\offset{-7}

% Black magic that works just fine and we should not have to worry about
\immediate\write18{echo '\mydate\space\mytime\space\offset hours' | sed -e 's/://' | xargs -0 date +\%Y-\%m-\%dT\%H:\%M:\%SZ -d > /tmp/date.txt}% 

% Write temporary file content to \ScriptResult. NOTE: Works
% Inspired from: http://tex.stackexchange.com/a/251574/38212
\newread\myscriptresult
\immediate\openin\myscriptresult=/tmp/date.txt
\read\myscriptresult to \ScriptResult
\immediate\closein\myscriptresult

% Print \ScriptResult. NOTE: Works
\noindent Return value read from \verb|/tmp/date.txt|: \ScriptResult\\

\DTMsavetimestamp{mytimestamp}{\ScriptResult}% TODO: This breaks compilation...
%\DTMsavetimestamp{mytimestamp}{2011-09-09T09:59:59Z}% ... whereas this works.

\noindent Date: \DTMusedate{mytimestamp}\\
\noindent Time: \DTMusetime{mytimestamp}

\end{document}

Restrictions

I am looking for a solution that continues to use the datetime2 package. If there is a solution that does not require writing to a temporary file /tmp/date.txt, that would actually be welcome (but it's not a priority).

Florian H.
  • 691
  • 3
  • 9
  • 1
    Your time is short a second as it's not in the form HH:MM:SS. – Werner Jul 20 '16 at 16:47
  • I don't understand what offset does in the above... Can you explain? – Werner Jul 20 '16 at 16:48
  • I don't think it's an expansion problem. I think it may be a category code problem. – Nicola Talbot Jul 20 '16 at 16:56
  • @Werner: The \write18 command takes care of the "missing second" and outputs an ISO-formatted timestamp, based on the given date, time, and \offset, which is interpreted as an offset in hours (that's the date/time arithmetic bit). However, this part works like a charm and should not even have to be understood in detail to solve this problem. – Florian H. Jul 20 '16 at 17:03
  • @FlorianH.: Then try with \begingroup\edef\x{\endgroup\noexpand\DTMsavetimestamp{\ScriptResult}}\x. – Werner Jul 20 '16 at 17:04
  • @Werner: \offset adds or subtracts a given number of hours to the timestamp defined by \mydate and \mytime. That's why I need GNU date. Your first solution above bypasses GNU date (and hence the ability to compute the offset). Your second solution gives me a Runaway argument? ! Paragraph ended before \DTMsavetimestamp was complete. – Florian H. Jul 20 '16 at 17:06
  • @NicolaTalbot: Quite possible; in my restricted TeX universe, expansion and category codes are just two synonyms for compilation hell :) Do you think I should edit the question's title accordingly? Any further pointers? – Florian H. Jul 20 '16 at 17:11

1 Answers1

2

It works fine using piped input instead:

\documentclass{article}

\usepackage{datetime2}

\begin{document}

\def\mydate{2015-01-01}%
\def\mytime{12:23}%
\def\offset{-7}

\makeatletter
\begingroup\endlinechar=-1\relax
\edef\pc{\expandafter\@gobble\string\%}
\everyeof{\noexpand}%
\edef\x{\endgroup\def\noexpand\ScriptResult{%
 \@@input|"echo '\mydate\space\mytime\space\offset hours'
   | sed -e 's/://'
   | xargs -0 date +\pc Y-\pc m-\pc dT\pc H:\pc M:\pc SZ -d" }}\x

\makeatother

Result: \ScriptResult

\DTMsavetimestamp{mytimestamp}{\ScriptResult}

\noindent Date: \DTMusedate{mytimestamp}\\
\noindent Time: \DTMusetime{mytimestamp}

\end{document}

Produces:

image of result

I'm guessing that the writing to file and reading back is introducing a category code change for one or more of the characters that are part of the syntax. The same error occurs if I try:

\documentclass{article}

\usepackage{datetime2}

\begin{document}
\edef\ScriptResult{\detokenize{2015-01-01T05:23:00Z}}

Result: \ScriptResult

\DTMsavetimestamp{mytimestamp}{\ScriptResult}

\noindent Date: \DTMusedate{mytimestamp}\\
\noindent Time: \DTMusetime{mytimestamp}

\end{document}

Alternatively, there's something subtly different in the result when reading in date.txt that I haven't noticed.

Edit: It's occurred to me that the original problem might have been due to a spurious space added to the end of \ScriptResult when reading from date.txt, which would probably have caused the same error message.

Nicola Talbot
  • 41,153
  • This works beautifully, and I'd like to accept it as an answer. However, when I try to move from my MWE to the real-world example, compilation fails for some reason with a Improper \spacefactor message. I am guessing this is triggered by \space, but I have no idea why the error appears not in my MWE, but only in my larger project. Any ideas? Or if not, perhaps workarounds that do not require \space altogether? I should mention that I am actually reading \mydate and \mytime from a .csv file via \usepackage{datatool} (but that does not seem to cause this particular issue). – Florian H. Jul 20 '16 at 18:14
  • Possible pointer to the cause of the Improper \spacefactor error: http://www.tex.ac.uk/FAQ-atvert.html – Florian H. Jul 20 '16 at 18:22
  • @FlorianH. Yes, improper space factor often indicates that you're using internal commands (ones with @ in the name) when @ is not considered a letter. (That's why my MWE has \makeatletter ... \makeatother) – Nicola Talbot Jul 20 '16 at 18:23
  • Mmh, but I am using \makeatletter ... \makeatother in my real-world project, and still I get that error. Need to investigate further, I guess. – Florian H. Jul 20 '16 at 18:29
  • It turns out that if the Improper \spacefactor error is thrown in my real-world project only in presence of \DTMsavetimestamp{mytimestamp}{\ScriptResult}. If I comment that command, plus the \DTMusedate and \DTMusetime commands, the project compiles fine as well. Any ideas? – Florian H. Jul 20 '16 at 20:38
  • It turned out that in my real-world project, I had used the \makeatletter ... \makeatother sequence (which Nicola had contributed above) inside an instance of a custom macro of mine. Once I pulled out the \makeatletter ... \makeatother such as to envelop the entire macro instance, things compiled just fine. This is what gave me the idea: https://tex.stackexchange.com/questions/201348/why-doesnt-makeatletter-work-inside-newcommand . I'll except Nicola's answer. – Florian H. Jul 20 '16 at 21:16