5

I am trying to pass a list of dates to a calendar using a pgf key, so that I can use it in different parts of the code.

Follow the PGF & TIKZ manual, I got it for mybirthday (see code below). However, a similar idea does not work in myholidays. How can i fix it? By the way, is there a better solution to define a "list" (or array, etc) of dates to achieve it?

\documentclass[12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calendar}

\newcommand\myweekdayname[1]{\ifcase#1M\or T\or W\or T\or F\or S\or S\fi}

\pgfkeys{/pgf/calendar/mybirthday/.code={
    \ifnum\pgfcalendarifdatemonth=1\relax
        \ifnum\pgfcalendarifdateday=20\relax
            \pgfcalendarmatchestrue
        \fi\fi}}

\pgfkeys{/pgf/calendar/myholidays/.code={
    \foreach \m / \d in {1/4, 1/5, 1/6, 1/7, 1/8}{
        \ifnum\pgfcalendarifdatemonth=\m\relax
            \ifnum\pgfcalendarifdateday=\d\relax
                \pgfcalendarmatchestrue
            \fi\fi}}}

\begin{document}

\begin{tikzpicture}
    \calendar[
        dates=2021-01-01 to 2021-01-last,
        day list downward, day yshift = 1em,
        day code={
            \ifdate{weekend, mybirthday, myholidays}{
                \node[shape=coordinate]{}; % trick (1)
                }{
                \node[anchor = east]{\tikzdaytext};
                \node[anchor = west, gray]{\myweekdayname{\pgfcalendarcurrentweekday}};
                }},
        execute after day scope={
            \ifdate{weekend, mybirthday, myholidays}{\pgftransformyshift{1em}}{};
            \ifdate{Sunday}{\pgftransformyshift{-0.5em}}{} % week skip
            }       
        ];
\end{tikzpicture}

\end{document}

(1) Calendar with TikZ; only print week days

2 Answers 2

5

The loop body of \foreach is enclosed in a group, so changes with \let, \def and derived commands stay local, are forgotten at the end of the loop.

Since \pgfcalendarmatchestrue is defined as \let \ifpgfcalendarmatches \iftrue, it suffices to add \global in front:

\pgfkeys{/pgf/calendar/myholidays/.code={
    \foreach \m / \d in {1/4, 1/5, 1/6, 1/7, 1/8}{
        \ifnum\pgfcalendarifdatemonth=\m\relax
            \ifnum\pgfcalendarifdateday=\d\relax
                \global\pgfcalendarmatchestrue
            \fi\fi}}}
1

You don't really need your own calendar .codes there.

The calendar library already has equals, that way you can just do

my birthday/.style={equals=01-20}

For the holidays, you could just define

my holidays/.style={
  equals=1-4, equals=1-5, equals=1-6, equals=1-7, equals=1-8}

or even just

my holidays/.style={between=1-4 and 1-8}

But if you want to specify a comma seperated list of dates formatted <month>/<day> you can use the .list handler (it uses \foreach but without the grouping):

my holidays/.style={@my holidays/.list={1/4, 1/5, 1/6, 1/7, 1/8}},
@my holidays/.style args={#1/#2}{equals={#1-#2}},

Code

\documentclass[12pt,tikz]{standalone}
\usetikzlibrary{calendar}
\newcommand\myweekdayname[1]{\ifcase#1M\or T\or W\or T\or F\or S\or S\fi}
\pgfqkeys{/pgf/calendar}{
  my birthday/.style={equals=01-20},
  % A
  % my holidays/.style={@my holidays/.list={1/4, 1/5, 1/6, 1/7, 1/8}},
  % @my holidays/.style args={#1/#2}{equals={#1-#2}},
  % B
  % my holidays/.style={
  %   equals=1-4, equals=1-5, equals=1-6, equals=1-7, equals=1-8},
  % C
  my holidays/.style={between=1-4 and 1-8},
}

\begin{document}
\begin{tikzpicture}
\calendar[
  dates=2021-01-01 to 2021-01-last,
  day list downward, day yshift = 1em,
  day code={
    \ifdate{weekend, my birthday, my holidays}{}{
      \node[anchor = east]{\tikzdaytext};
      \node[anchor = west, gray]{\myweekdayname{\pgfcalendarcurrentweekday}};}},
  execute after day scope={
    \ifdate{weekend, my birthday, my holidays}{\pgftransformyshift{1em}}{}
    \ifdate{Sunday}{\pgftransformyshift{-0.5em}}{} % week skip
  }];
\end{tikzpicture}
\end{document}

Output

enter image description here

You must log in to answer this question.

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