9

I have dates formatted {yyyy-mm-dd}. I would like display the time elapsed between the dates in the form Y years, M months. Given the format of the dates, it seems easier to use arithmetic than to manipulate them as dates.

I am trying to call the macro with two date arguments, parsing each one of them. This is the part that is failing, I believe due to the interaction between the two date arguments and their separators. Is there a way to do this within the macro definition, or is it necessary to define another macro to act on each date argument separately?

\documentclass{article}

\newcount\elapsedyears
\newcount\elapsedmonths

\def\elapsedyearsmonths[#1-#2-#3]#4-#5-#6\relax{%
  \ifnum#2>#5
    \elapsedyears=\numexpr#1-#4
    \elapsedmonths=\numexpr#2-#5+1
  \else
    \elapsedyears=\numexpr#1-#4-1
    \elapsedmonths=\numexpr#2-#5+12
  \fi
  \the\elapsedyears{}years, \the\elapsedmonths{} months
}

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\elapsedmonthsyears{2014-11-06}{2012-02-03}

\elapsedmonthsyears\myenddate\mystartdate

\end{document}

I see now that I will have to create some more conditional statements to pluralise, or not, "year(s)" and "month(s)" also.

Cheers

1
  • 1
    You should take a look at the datetime package... ;).
    – cfr
    Nov 26, 2014 at 1:05

3 Answers 3

8
+50

As written, the posted code produces

! Undefined control sequence.
l.22 \elapsedmonthsyears

so changing the last two calls to use \elapsedyearsmonths

produces

! Use of \elapsedyearsmonths doesn't match its definition.
l.22 \elapsedyearsmonths{

as the call on line 22 is followed by a {

(the end of line in the error message shows TeX stopped at that point)

as as written the macro has a [ delimiter before #1 so must be followed by [.

Changing the calls to

\elapsedyearsmonths[2014-11-06]2012-02-03\relax

\elapsedyearsmonths[\myenddate]\mystartdate\relax

produces

! Paragraph ended before \elapsedyearsmonths was complete.
<to be read again> 
                   \par 
l.25 

which is good, it means that the first call did something, as the error is line 25.

The second call failed as TeX ran past the blank line, while looking for a - that is not there.

Adding a macro to expand the arguments:

\def\xelapsedyearsmonths#1#2{%
    \edef\tmp{\noexpand\elapsedyearsmonths[#1]#2\relax}%
    \tmp}

and changing the calls to

\xelapsedyearsmonths{2014-11-06}{2012-02-03}

\xelapsedyearsmonths\myenddate\mystartdate

It runs without error

enter image description here

\documentclass{article}

\newcount\elapsedyears
\newcount\elapsedmonths

\def\elapsedyearsmonths[#1-#2-#3]#4-#5-#6\relax{%
  \ifnum#2>#5
    \elapsedyears=\numexpr#1-#4
    \elapsedmonths=\numexpr#2-#5+1
  \else
    \elapsedyears=\numexpr#1-#4-1
    \elapsedmonths=\numexpr#2-#5+12
  \fi
  \the\elapsedyears{}years, \the\elapsedmonths{} months
}

\def\xelapsedyearsmonths#1#2{%
  \edef\tmp{\noexpand\elapsedyearsmonths[#1]#2\relax}%
  \tmp}

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\xelapsedyearsmonths{2014-11-06}{2012-02-03}

\xelapsedyearsmonths\myenddate\mystartdate

\end{document}
3
  • This working great, except calling \xelapsedyearsmonths results in a leading space that is messing up my formatting. Why?
    – Jonathan
    Nov 29, 2014 at 10:49
  • only space should be after months you can put an example in the question and ping me here if you have a reproducible test Nov 29, 2014 at 11:57
  • My mistake. I left out the % at the end of the first line of the \elapsedyearsmonths definition when copying the code.
    – Jonathan
    Nov 30, 2014 at 16:28
8

Here's an implementation with expl3:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

% the user level command; with :oo both arguments are expanded once
% before being processed
\NewDocumentCommand{\elapsedmonthsyears}{mm}
 {
  \jonathan_elapsed_months:oo{#1}{#2}
 }

% some variables for later usage
\seq_new:N \l_jonathan_end_date_seq
\seq_new:N \l_jonathan_start_date_seq
\int_new:N \l_jonathan_months_int

\cs_new_protected:Npn \jonathan_elapsed_months:nn #1 #2
 {
  % split the first argument into components {yearend}{monthend}[dayend}
  \seq_set_split:Nnn \l_jonathan_end_date_seq { - } { #1 }  
  % split the second argument into components {yearstart}{monthstart}[daystart}
  \seq_set_split:Nnn \l_jonathan_start_date_seq { - } { #2 }
  % compute d=(yearend*12+monthend)-(yearstart*12+monthstart)
  % which gives the difference in months
  \int_set:Nn \l_jonathan_months_int
   {
    (
     \seq_item:Nn \l_jonathan_end_date_seq { 1 } * 12 +
     \seq_item:Nn \l_jonathan_end_date_seq { 2 } 
    )
    -
    (
     \seq_item:Nn \l_jonathan_start_date_seq { 1 } * 12 +
     \seq_item:Nn \l_jonathan_start_date_seq { 2 } 
    )
   }
  % print the number of years, d/12 (truncated)
  \int_to_arabic:n { \int_div_truncate:nn { \l_jonathan_months_int } { 12 } }
  \nobreakspace
  year
  % if the number of years is =1 don't add an "s"
  \int_compare:nF { \int_div_truncate:nn { \l_jonathan_months_int } { 12 } = 1}{s}
  % print a comma with a space
  ,~
  % print the number of months, d mod 12
  \int_to_arabic:n { \int_mod:nn { \l_jonathan_months_int } { 12 } }
  \nobreakspace
  month
  % if the number of months is =1 don't add an "s"
  \int_compare:nF { \int_mod:nn { \l_jonathan_months_int } { 12 } = 1 }{s}
 }

% generate the :oo variant
\cs_generate_variant:Nn \jonathan_elapsed_months:nn { oo }
\ExplSyntaxOff

\begin{document}

\def\myenddate{2013-10-22}
\def\mystartdate{2010-09-15}

\elapsedmonthsyears{2014-11-06}{2012-02-03}

\elapsedmonthsyears\myenddate\mystartdate

\end{document}

enter image description here

1

Not good, but not too bad:

%begin time definitions
\newcount\eyear
\newcount\emonth
\newcount\eday
\newcount\ehour
\newcount\eminutes
% \time
\newcount\hour
\newcount\hours
\newcount\minutes
\hour=\time \divide\hour by 60 
\minutes=\time
\hours=\hour \multiply\hours by 60 
\advance \minutes by -\hours
\def\fromdate[#1-#2-#3 #4:#5]{%
\eyear=\year%
\emonth=\month%
\eday=\day%
\ehour=\hour%
\eminutes=\minutes%
\def\elapsed{%
\vskip1\baselineskip From Date #1-#2-#3 #4:#5\vskip1\baselineskip%
\advance\eyear by -#1 \multiply\eyear by-1%
\advance\emonth by-#2 \multiply\emonth by-1%
\advance\eday by -#3 \multiply\eday by-1%
\advance\ehour by -#4 \multiply\ehour by-1%
\advance\eminutes by -#5 \multiply\eminutes by-1%
 Difference (Years:\the\eyear)-(Months:\the\emonth)-(Days:\the\eday)%
(Hours:\the\ehour):(Minutes:\the\eminutes)
}%
Current Date \the\year-\the\month-\the\day\ \ifnum\hour<10%
0\fi\the\hour:\ifnum\minutes<10 0\fi\the\minutes%
\elapsed%
\vskip2\baselineskip
}%
\fromdate[2013-10-3 1:10]
\fromdate[2012-1-30 23:10]
\fromdate[2010-12-10 3:10]
%end  \time defintions
\bye

output

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .