# datetime2's \DTMsavetimestamp can't read from macro - expansion or catcode issue?

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
\immediate\openin\myscriptresult=/tmp/date.txt
\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).

• 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

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:

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.

• 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: 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