3

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

Jonathan
  • 139
  • Please post a *complete* small document people can compile to reproduce the problem. That is much more useful than mere code fragments. – cfr Nov 05 '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 05 '14 at 23:04
  • @cfr "some people" had already got a complete document with that code in their emacs buffer since yesterday:-) – David Carlisle Nov 05 '14 at 23:08
  • @DavidCarlisle ???? – cfr Nov 05 '14 at 23:17
  • 1
    @cfr the macro is from an answer of mine, still in my editor from yesterday;-) – David Carlisle Nov 05 '14 at 23:18
  • @DavidCarlisle Oh, I see. Sorry. Any mention of emacs tends to elicit an extremely confused response from me. (vim) What does the \def#8 part of your answer do? Why \def? \def what? – cfr Nov 05 '14 at 23:23
  • 2
    @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 05 '14 at 23:26
  • 1
    @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 05 '14 at 23:30
  • @cfr Fair enough, it wouldn't have taken much to add the whole of my own test document. Noted. The truth is, as a newb I am usually looking more for advice on techniques than solutions to specific things. "Teach a man to fish..." and all that. – Jonathan Nov 06 '14 at 08:45

3 Answers3

6

enter image description here

\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}
David Carlisle
  • 757,742
  • 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 06 '14 at 09: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 06 '14 at 10:49
6

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

enter image description here

\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.

Werner
  • 603,163
4

Here is a version using the xstring package:

enter image description here

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}

Peter Grill
  • 223,288
  • 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 06 '14 at 08: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 06 '14 at 16:39