Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I wrote some code for finding the date of Easter. Now I want to use it with the TiKZ calendar to mark the Easter related holidays.

Here's what I have so far:

\documentclass{scrartcl}
\usepackage[T1]{fontenc}
\usepackage{libertine}
\usepackage[margin=5pt,a5paper,landscape]{geometry}
\setlength{\parindent}{0pt}

\usepackage{tikz}
\usetikzlibrary{calendar}

\usepackage{expl3}

\ExplSyntaxOn

%% Knuth's AoCP, vol 1, 2nd ed, pp 155--156
\int_new:N \l_easter_Y_int
\int_new:N \l_easter_G_int
\int_new:N \l_easter_C_int
\int_new:N \l_easter_X_int
\int_new:N \l_easter_Z_int
\int_new:N \l_easter_D_int
\int_new:N \l_easter_E_int
\int_new:N \l_easter_N_int
\int_new:N \l_easter_M_int

\cs_new:Nn \easter_sunday:n {

  \int_set:Nn \l_easter_Y_int { #1 }

  \int_set:Nn \l_easter_G_int {
    \int_mod:nn { \l_easter_Y_int } { 19 } + 1
  }

  \int_set:Nn \l_easter_C_int {
    \int_div_truncate:nn { \l_easter_Y_int } { 100 } + 1
  }

  \int_set:Nn \l_easter_X_int {
    \int_div_truncate:nn { 3 * \l_easter_C_int } { 4 } - 12
  }

  \int_set:Nn \l_easter_Z_int {
    \int_div_truncate:nn { 8 * \l_easter_C_int + 5 } { 25 } - 5
  }

  \int_set:Nn \l_easter_D_int {
    \int_div_truncate:nn { 5 * \l_easter_Y_int } { 4 } - \l_easter_X_int - 10
  }

  \int_set:Nn \l_easter_E_int {
    \int_mod:nn { 11 * \l_easter_G_int + 20 + \l_easter_Z_int
      - \l_easter_X_int } { 30 }
  }

  % \int_mod:nn behaves strangely.
  \int_compare:nNnT { \l_easter_E_int } < { 0 }
  {
    \int_add:Nn \l_easter_E_int { 30 }
  }

  \int_compare:nNnTF { \l_easter_E_int } = { 25 }
  { % true
    \int_compare:nNnT { \l_easter_G_int } > { 11 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }
  { % false
    \int_compare:nNnT { \l_easter_E_int } = { 24 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }

  \int_set:Nn \l_easter_N_int { 44 - \l_easter_E_int }

  \int_compare:nNnT { \l_easter_N_int } < { 21 }
  { % true
    \int_add:Nn \l_easter_N_int { 30 }
  }

  \int_add:Nn \l_easter_N_int {
    7 - \int_mod:nn { \l_easter_D_int + \l_easter_N_int } { 7 }
  }

  \int_compare:nNnTF { \l_easter_N_int } > { 31 }
  { % true
    \int_sub:Nn \l_easter_N_int { 31 }
    \int_set:Nn \l_easter_M_int { 4 } % April
  }
  { % false
    \int_set:Nn \l_easter_M_int { 3 } % March
  }

}

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
  \calendar[dates=2012-04-01 to 2012-05-last, week list];
\end{tikzpicture}

\end{document}
share|improve this question
add comment

2 Answers

up vote 19 down vote accepted

The trick was to use the command \pgfkeys.

Here is the full code:

\documentclass{scrartcl}
\usepackage[T1]{fontenc}
\usepackage{libertine}
\usepackage[margin=5pt,a5paper,landscape]{geometry}
\setlength{\parindent}{0pt}

\usepackage{tikz}
\usetikzlibrary{calendar}

\usepackage{expl3}

\ExplSyntaxOn

%% Knuth's AoCP, vol 1, 2nd ed, pp 155--156
\int_new:N \l_easter_Y_int
\int_new:N \l_easter_G_int
\int_new:N \l_easter_C_int
\int_new:N \l_easter_X_int
\int_new:N \l_easter_Z_int
\int_new:N \l_easter_D_int
\int_new:N \l_easter_E_int
\int_new:N \l_easter_N_int
\int_new:N \l_easter_M_int
\int_new:N \l_easter_julian_day_int

\cs_new:Nn \easter_sunday:n {

  \int_set:Nn \l_easter_Y_int { #1 }

  \int_set:Nn \l_easter_G_int {
    \int_mod:nn { \l_easter_Y_int } { 19 } + 1
  }

  \int_set:Nn \l_easter_C_int {
    \int_div_truncate:nn { \l_easter_Y_int } { 100 } + 1
  }

  \int_set:Nn \l_easter_X_int {
    \int_div_truncate:nn { 3 * \l_easter_C_int } { 4 } - 12
  }

  \int_set:Nn \l_easter_Z_int {
    \int_div_truncate:nn { 8 * \l_easter_C_int + 5 } { 25 } - 5
  }

  \int_set:Nn \l_easter_D_int {
    \int_div_truncate:nn { 5 * \l_easter_Y_int } { 4 } - \l_easter_X_int - 10
  }

  \int_set:Nn \l_easter_E_int {
    \int_mod:nn { 11 * \l_easter_G_int + 20 + \l_easter_Z_int
      - \l_easter_X_int } { 30 }
  }

  % \int_mod:nn behaves strangely.
  \int_compare:nNnT { \l_easter_E_int } < { 0 }
  {
    \int_add:Nn \l_easter_E_int { 30 }
  }

  \int_compare:nNnTF { \l_easter_E_int } = { 25 }
  { % true
    \int_compare:nNnT { \l_easter_G_int } > { 11 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }
  { % false
    \int_compare:nNnT { \l_easter_E_int } = { 24 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }

  \int_set:Nn \l_easter_N_int { 44 - \l_easter_E_int }

  \int_compare:nNnT { \l_easter_N_int } < { 21 }
  { % true
    \int_add:Nn \l_easter_N_int { 30 }
  }

  \int_add:Nn \l_easter_N_int {
    7 - \int_mod:nn { \l_easter_D_int + \l_easter_N_int } { 7 }
  }

  \int_compare:nNnTF { \l_easter_N_int } > { 31 }
  { % true
    \int_sub:Nn \l_easter_N_int { 31 }
    \int_set:Nn \l_easter_M_int { 4 } % April
  }
  { % false
    \int_set:Nn \l_easter_M_int { 3 } % March
  }

  \pgfcalendardatetojulian { \l_easter_Y_int -
    \l_easter_M_int - \l_easter_N_int
  } { \l_easter_julian_day_int }

}

\pgfkeys{/pgf/calendar/Easter/.default = 0}
\pgfkeys{/pgf/calendar/Easter/.code =
  {
    \easter_sunday:n { \pgfcalendarifdateyear }
    \int_compare:nNnT { \pgfcalendarifdatejulian }
    =  {\l_easter_julian_day_int + #1}
    { \pgfcalendarmatchestrue }
  }
}

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
  \calendar[dates=2012-04-01 to 2012-05-last, week list]
    if (Easter=-3, % Maundy Thursday
        Easter=-2, % Good Friday
        Easter,    % Easter Sunday
        Easter=1,  % Easter Monday
        Easter=39, % Feast of the Ascension
        Easter=49, % Pentecost
        Easter=50) % Whit Monday
    [red];
\end{tikzpicture}

\end{document}

Here is the result:

calendar

Here is an expanded version: http://pastebin.com/KYngbPGQ

There is also a version here: http://www.texample.net/tikz/examples/birthday-calendar/

Please note that this solution requires an up-to-date TeX distro. It won’t work with the distro that comes with Ubuntu 12.04 and older.

share|improve this answer
1  
Shouldn't this be made into a package? (Or incorporated into tikz itself?) –  mbork Jun 11 '12 at 12:53
    
@mbork I've already added a feature request. I need to convert the code to something generic (no latex3). –  cjorssen Jun 22 '12 at 7:43
    
@cjorssen Would my answer help? :) –  Qrrbrbirlbel Nov 10 '13 at 5:11
    
@Qrrbrbirlbel Sure :) I'll add it ASAP. –  cjorssen Nov 10 '13 at 15:21
add comment

The same code but with TeX counts.

The formula from WikiBooks: Algorithmensammlung: Kalendar: Feiertage was used.

Due to the nature of the test, if one uses an argument to Easter (e.g. Eastern=365) so that the actual day to test against lies not in the current year, this will fail. (You cannot test a day from year 2013 that lies somehow relatively to Eastern in 2012.)

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calendar}
\makeatletter
\def\pgfcalendar@Easter#1{%
 \begingroup
   \count0=#1\relax              % Yeah 0
   \count1=\count0%              % K 1
   \divide\count1 100            % K 1
   \count2=\count1               % M 3
   \multiply\count2 3
   \advance\count2 3
   \divide\count2 4              % 2 holds (3 * K +3) \ 4
   \count3=\count1
   \multiply\count3 8
   \advance\count3 13
   \divide\count3 -25
   \advance\count3\count2
   \advance\count3 15           % M 3
   \count2-\count2              % S 2
   \advance\count2 2
   \count4=\count0              % A 4
   \divide\count4 19
   \multiply\count4 -19
   \advance\count4\count0       % A 4
   \count1=\count4              % D 1 *
   \multiply\count1 19
   \advance\count1\count3
   \count5\count1
   \divide\count1 30
   \multiply\count1 -30
   \advance\count1\count5       % D 1 *
   \divide\count4 11            % R 4 *
   \advance\count4\count1
   \divide\count4 29            % R 4 *
   \advance\count1-\count4      % OG 1 **
   \advance\count1 21           % OG 1 **
   \count3\count0               % SZ 3 *
   \divide\count3 4
   \advance\count3\count0
   \advance\count3\count2
   \count4-\count3
   \divide\count3 7
   \multiply\count3 7
   \advance\count3\count4
   \advance\count3 7           % SZ 3 *
   \count4-\count3             % OE 4 **
   \advance\count4\count1
   \count3-\count4
   \divide\count4 7
   \multiply\count4 7
   \advance\count4\count3
   \advance\count4 7           % OE 4 **
   \advance\count4\count1
   \pgfcalendardatetojulian{\the\count0-03-\the\count4}\pgfutil@tempcnta
   \expandafter\xdef\csname pgfcalendar@Easter@\the\count0\endcsname
     {\the\pgfutil@tempcnta}%
 \endgroup}
\pgfqkeys{/pgf/calendar/Easter}{
  .default=0,
  .code={%
      \expandafter\ifx\csname pgfcalendar@Easter@\pgfcalendarifdateyear\endcsname\relax
        \pgfcalendar@Easter{\pgfcalendarifdateyear}%
      \fi
      \expandafter\pgfutil@tempcnta
        \csname pgfcalendar@Easter@\pgfcalendarifdateyear\endcsname
      \advance\pgfutil@tempcnta#1\relax
      \ifnum\pgfcalendarifdatejulian=\pgfutil@tempcnta
        \pgfcalendarmatchestrue
      \fi}}
\makeatother
\begin{document}
\begin{tikzpicture}
  \calendar[dates=2012-04-01 to 2012-05-last, week list]
    if (Easter=-3, % Maundy Thursday
        Easter=-2, % Good Friday
        Easter,    % Easter Sunday
        Easter=1,  % Easter Monday
        Easter=39, % Feast of the Ascension
        Easter=49, % Pentecost
        Easter=50) % Whit Monday
    [red];
\end{tikzpicture}
\end{document}

Output

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.