[Tex/LaTex] Determine last day of given month

datetimemacros

I want to determine how many days there are in a particular month.

Using the datenumber package, I thought I could simply set the date to the 1st of the next month and then back up one day would be the end of the month and extract the date. Well that sure seemed simple when I came up with it, but then got stuck at actually extracting the day of the month.

So, what do I need to replace

\xdef\LastDayOfMonth{\value{dateday}}

with the get the number of days in the month.

Notes:

  • I am not opposed to additional packages, so any package solution is fine.

Code:

\documentclass{article}
\usepackage{datenumber}
\usepackage{pgffor}

\newcounter{GivenDateCounter}
\newcommand{\LastDayOfMonth}{XX}%
\newcommand{\NumberOfDaysInMonth}[2]{%
    % #1 = YYYY
    % #2 = MM
    \ifnum#2<12\relax
        % Since this is NOT Dec we can just go to the 1st of the next
        % month and back up one day.
        \setmydatenumber{GivenDateCounter}%
                {#1}%
                {\numexpr#2+1\relax}% Next month
                {01}% First of the month
    \else
        % Since this IS Dec we can just go to Jan 1st of the next
        % year and back up one day.
        \setmydatenumber{GivenDateCounter}%
                {\numexpr#1+1\relax}% Next Year
                {01}% Next day is Jan next year since current month is 12
                {01}% First of the month
    \fi
    \addtocounter{GivenDateCounter}{-1}% Now we are the end of the required month
    \xdef\LastDayOfMonth{\value{dateday}}%  <---- Stuck here.
    \typeout{**** \string\LastDayOfMonth for #1-#2=\LastDayOfMonth}%
}%

\begin{document}

\foreach \YearNumber in {2013, 2014} {%
    \foreach \MonthNumber in {01, 02, ..., 12} {%
        \par
        Number of Days in \YearNumber-\MonthNumber{} is 
        \NumberOfDaysInMonth{\YearNumber}{\MonthNumber}.%
    }%
}%


\end{document}

Best Answer

I'd say to use \arabic{dateday}, since \value{dateday} is not expandable (it expands to the registers name, not to the value). However it doesn't work, because dateday is not set.

Since you're not bound to datetime, here's a version with xparse.

\documentclass{article}
\usepackage{xparse,pgffor,multicol}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand\NumberOfDaysInMonth { m m }
 {
  \grill_numb_days_month:nn { #1 } { #2 }
 }

\cs_new:Npn \grill_numb_days_month:nn #1 #2
 {
  \int_case:nn { #2 }
   {
    {1}{31}
    {2}{ \grill_if_leap_year:nTF { #1 } { 29 } { 28 } }
    {3}{31}
    {4}{30}
    {5}{31}
    {6}{30}
    {7}{31}
    {8}{31}
    {9}{30}
    {10}{31}
    {11}{30}
    {12}{31}
   }
 }

\prg_new_conditional:Npnn \grill_if_leap_year:n #1 { p,T,F,TF }
 {
  \bool_if:nTF
   {
    \int_compare_p:n { \int_mod:nn { #1 } { 4 } != 0 }
    ||
    (
     \int_compare_p:n { \int_mod:nn { #1 } { 4 } == 0 }
     &&
     \int_compare_p:n { \int_mod:nn { \int_div_truncate:nn { #1 } { 100 } } { 4 } != 0 }
    ) 
   }
   { \prg_return_false: }
   { \prg_return_true: }
 }

\ExplSyntaxOff

\begin{document}
\begin{multicols}{2}

\foreach \YearNumber in {1900, 2000, 2012, 2013} {%
    \foreach \MonthNumber in {1, 2, ..., 12} {%
        \par
        Number of Days in \YearNumber-\MonthNumber{} is 
        \NumberOfDaysInMonth{\YearNumber}{\MonthNumber}.%
    }
}

\end{multicols}

\end{document}

Note that \NumberOfDaysInMonth is fully expandable, so

\edef\MDCCFebruary{\NumberOfDaysInMonth{1700}{2}}

would define the macro to expand to 28.

enter image description here

The conditional command \grill_if_leap_year:nTF can also be used in other situations. It has the four forms: predicate, true, false and true/false.