# Check macro argument has correct format

I have a macro which will read in arguments in date format e.g. {2012-11-08}

\usepackage{datetime}

\def\customdate#1#2#3#4-#5-#6\relax{%
\shortmonthname[#5] '#3#4%
}


However, in some instances I would like the output to print something else in place of a date, perhaps "Present", "ongoing" or some other string. I had hoped to use some kind of if-statement or use an on-error type command, but I cannot find anything appropriate.

How can I write another macro, or add some kind of conditional statement to the above macro so that it will output the date formatted as requested, but will return the argument unchanged if it does not have the "####-##-##" format?

Cheers

• Please post a complete small document people can compile to reproduce the problem. That is much more useful than mere code fragments. – cfr Nov 5 '14 at 22:41
• What do you expect in the argument of \customdate? You should have something in mind. Also, what a non standard argument should print? – egreg Nov 5 '14 at 23:04
• @cfr the macro is from an answer of mine, still in my editor from yesterday;-) – David Carlisle Nov 5 '14 at 23:18
• @cfr it's not surprising you're confused if you use vi(m) :-) \def (like \relax in this context) is just some arbitrary token that's not expected to appear in the input, #8 is the original string used in the case a ? was seen (it would be possible to reconstitute the original string from the earlier # but just keeping it is easier. – David Carlisle Nov 5 '14 at 23:26
• @DavidCarlisle Thank you. (But vim is one of the few things which makes some sort of sense in an alien and hostile world harbouring emacs. ;).) – cfr Nov 5 '14 at 23:30

You're not using argument #6, so the following is sufficient in order to distinguish between valid/invalid arguments:

\documentclass{article}

\usepackage{datetime}

\def\customdate#1#2#3#4-#5-#6\relax{%
\if?#5?
#1#2#3#4
\else
\shortmonthname[#5] '#3#4%
\fi
}

\newcommand{\mydate}[1]{\expandafter\customdate#1--\relax}

\begin{document}

\mydate{2014-11-04}

\mydate{today}

\mydate{now}

\mydate{2014-11}

\end{document}


We pass -- as additional delimiters before processing the argument to \mydate. This way you'll be guaranteed that \customdate is passed at least two -'s. A check is made to see whether #5 is empty to condition on the special formatting.

Of course, all sorts of bad things can happen if the format is adhered to, but invalid arguments are passed (like \mydate{2014-a}). Those aren't tested for here.

• Thanks @Werner. Very elegant. I am choosing this answer because it does exactly what I want, with few lines of code. My application is pretty well controlled, so I can see what I am passing to the macro and read the error output. Question(s) if?#5? - when #5 is empty does it compare ? to ? and return true? What does ? mean in this context? Any advice on where I could find out more about things like this ? token (I am struggling to find any reference to it in tutorials, etc.) Thanks again – Jonathan Nov 6 '14 at 9:01
• @Jonathan: That's exactly it. If #5 is empty, then ? is compared to ? (which is just a question mark token). Some post that might be of interest here include: What does \ifx\\#1\\ stand for?; Difference between \if and \ifx and Different command definitions with and without optional argument – Werner Nov 6 '14 at 15:18

\documentclass{article}

\def\shortdate#1{\ifcase#1\relax\or
Jan\or Feb\or Mar\or Apr\or May\or Jun\or
Jul\or Aug\or Sep\or Oct\or Nov\or Dec\fi}

\def\mydate#1{\xmydate#1\relax????-?-?\relax\def{#1}}

\def\xmydate#1#2#3#4-#5-#6\relax#7\def#8{%
\ifx?#5%
#8%
\else
\shortdate{#5} '#3#4%
\fi}

\begin{document}

\mydate{2014-11-04}

\mydate{today}

\mydate{now}

\end{document}

• Thanks once again, David. But what do all these ? mean? Does this token have a special meaning (can't find any reference to it anywhere yet)? Am I correct that in \xmydate the \relax and \def are like separators? Is \mydate calling \xmydate with the concatenation of the orignal argument, question marks and the original argument repeated? – Jonathan Nov 6 '14 at 9:25
• the trick with tex parsing is to always give the macro some argunment of the right form so it needs something between tow - and \relax so give it ??-?-?\relax then if you actually get a ? the data was not th eright form. doesn't have top be ? any non digit would do – David Carlisle Nov 6 '14 at 10:49

Here is a version using the xstring package:

## Further Enhancements:

• Check that the year is actually four digits, and in the valid range.
• Check that the month is 1-12.
• Check that the day of the month is valid for the given year and month.

## Code:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage{datetime}
\usepackage{xstring}
\usepackage{etoolbox}

%% http://tex.stackexchange.com/questions/50111/how-to-check-if-the-value-of-a-parameter-is-a-number/50113#50113
\newcommand*{\IsInteger}[3]{%
\IfStrEq{#1}{ }{%
#3% is a blank string
}{%
\IfInteger{#1}{#2}{#3}%
}%
}%

\newcommand*{\ExtractedYear}{}
\newcommand*{\ExtractedTwoDigitYear}{}
\newcommand*{\ExtractedMonth}{}
\newcommand*{\ExtractedDay}{}
\newtoggle{IfProperlyFormattedDate}
\newcommand*{\mydate}[1]{%
\StrBefore{#1}{-}[\ExtractedYear]%
\toggletrue{IfProperlyFormattedDate}%
\IsInteger{\ExtractedYear}{%
\StrGobbleLeft{\ExtractedYear}{2}[\ExtractedTwoDigitYear]%
\StrBetween[1,2]{#1}{-}{-}[\ExtractedMonth]%
\IsInteger{\ExtractedMonth}{%
\StrBehind[2]{#1}{-}[\ExtractedDay]%
\IsInteger{\ExtractedDay}{}{\togglefalse{IfProperlyFormattedDate}}%
}{%
\togglefalse{IfProperlyFormattedDate}%
}%
}{%
\togglefalse{IfProperlyFormattedDate}%
}%
\makebox[2.0cm][r]{#1:}~% For debuggging
\iftoggle{IfProperlyFormattedDate}{%
\shortmonthname[\ExtractedMonth] \textquotesingle\ExtractedTwoDigitYear%
}{%
#1%
}%
}

\begin{document}
\mydate{2014-11-04}\par
\mydate{ABCD-Nov-04}\par
\mydate{220x-Nov-04}\par
\mydate{2001-xxx-04}\par
\mydate{2001-12-x}\par
\mydate{today}\par
\mydate{now}\par
\end{document}

• Wow, great solution, and all in LaTeX. Easy to understand for not using primitives, but that is a lot of code for something I thought would be simple. Thanks for the help Peter. – Jonathan Nov 6 '14 at 8:43
• @Jonathan: The readability is usually the reason I prefer using xstring. The amount of code is dependent on exactly how much error checking you want to do. I usually prefer more through testing so as to minimize further the chance of incorrect output. – Peter Grill Nov 6 '14 at 16:39