5

I would like to specially mark national holidays in my calendar. Some of the rules are "First Monday in June" and "Last Monday in October".

I have been looking at the example on p. 280 of the PGF 2.10 manual but I'm not able ot modify it for my purposes. The useful parts of this example are:

if (between=\year-\month-\day+8 and \year-\month-\day+10)
  [red]
if (Sunday)
  [gray,nodes={draw=none}]

Here's an MWE, I believe.

% Based on Hakon Malmedal's 'Birthday calendar' from TeXamples
\documentclass[fontsize=20pt]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{calendar,fit}

\begin{document}

\begin{tikzpicture}[thick]
  \calendar[dates=2014-01-01 to 2014-01-last,
            week list,
            month label above centered,
            month text=\textsc{\%mt \%y0}]
  if (equals=01-01,
      equals=03-17,
      equals=12-25,
      equals=12-26) [orange]
      % p. 280 of PGF 2.10 manual is useful
  if (between=2014-01-08 and 2014-01-14) [orange]
% following doesn't work:
%  if (Monday \AND between=2014-01-08 and 2014-01-14) [orange]
;
\end{tikzpicture}

\end{document}

The 7 days from 8th to 14th of Jan. get displayed in orange but I would like simply the Monday (2nd Monday of month) to be in orange, as intended by the commented line.

How can I build a conjunction of two conditions so that the holiday is printed in orange?

3
  • 1
    Please add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}.
    – jub0bs
    Oct 27, 2013 at 13:40
  • Do you also need easter rules? Perhaps you can use parts of the answer in tex.stackexchange.com/questions/57218/…
    – knut
    Oct 27, 2013 at 18:53
  • @knut: as the comment at the top of my MWE suggests it is based on the link you mention. The rules there are very useful but they don't solve the problem of finding the kth Monday in the month. Nor does the PGF guide.
    – healyp
    Oct 27, 2013 at 20:22

1 Answer 1

10

A simple and function

If you simply want an and function for PGF’s calendar you can use the following code. It checks the first argument and only if it is true it does check the other one. (If the first one's already false, why bother checking the second?)

This can be used as

if (and={between=2014-01-08 and 2014-01-14}{Monday}) [orange];

Maybe it is better to write

if (between=2014-01-08 and 2014-01-14, And=Monday, And=…) [orange];

This works, too. Obviously, you'll need {} if you use it like this:

if (Monday, And={between=2014-01-08 and 2014-01-14}) [orange];

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calendar}
\makeatletter
\pgfqkeys{/pgf/calendar}{
  and/.code 2 args=%
    \begingroup
      \let\pgf@cal@temp\pgfutil@empty
      \pgfcalendar@launch@ifdate{#1}{\pgfcalendar@launch@ifdate{#2}{\def\pgf@cal@temp{\let\ifpgfcalendarmatches\iftrue}}{}}{}%
    \expandafter\endgroup\pgf@cal@temp,
  And/.code=%
    \begingroup
      \let\pgf@cal@temp\pgfutil@empty
      \ifpgfcalendarmatches\expandafter\pgfutil@firstofone\else\expandafter\pgfutil@gobble\fi
      {\pgfcalendar@launch@ifdate{#1}{\def\pgf@cal@temp{\let\ifpgfcalendarmatches\iftrue}}{}}%
    \expandafter\endgroup\pgf@cal@temp}
\makeatother
\begin{document}
\begin{tikzpicture}
  \calendar[dates=2014-01-01 to 2014-01-last, week list,
            month label above centered, month text=\textsc{\%mt \%y0}]
  if (equals=01-01, equals=03-17, equals=12-25, equals=12-26) [orange]
  if (between=2014-01-08 and 2014-01-14, And=Monday)          [orange]
  if (and={between=2014-01-08 and 2014-01-14}{Monday})        [days={fill=gray}];
\end{tikzpicture}
\end{document}

Output

enter image description here

Second Sunday in May?

This library qrr.calendar introduces the conditionals

  • leap year

    This can also be used for other years:

      2000 was\ifdate{leap year=200}{}{ not} a leap year
    
  • week of month=<arg> tests whether we are in the <arg>th week of the month. This does not correspond with the Monday-to-Sunday (or the Sunday-to-Saturday) week. The first week goes from day 1 to day 7, the second week from day 8 to 14, and so on.

  • week of month'=<arg> is the same as week of month but from the last day on.

    week of month'=1 would (currently: October) test whether we are between day 25 and day 31 of the month. This uses the \pgfcalendar@getlastYMX macro to get the last day of a month which uses the leap year key when the month falls on February.

  • first=[<i>:]<conditonal> and last=[<i>:]<conditional> combines week of month and week of month' with <conditional>. You can check for the second Monday in a month with

     first=2:Monday
    

    If no <i>: is given, the first/last (i.e. 1:) is used.

    The <conditional> can actually be anything but naturally you want to specify a day of the week here.

  • between days=<first> and <last> checks wheter the day is between first and <last>.

  • not=<cond> negates the outcome of <cond>


Load it with

\usetikzlibrary{qrr.calendar}
% or
\usepgflibrary{qrr.calendar}

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{calendar,qrr.calendar}\usepackage{libertine}
\begin{document}\sffamily
\begin{tikzpicture}
  \calendar[dates=2023-01-01 to 2023-12-31, month list, month label left,
    month yshift={!mod(\numexpr\pgfcalendarcurrentmonth-1\relax,3)*.25em+1.25em}]
    if (Sunday) [black!50]
    if (first=2:Sunday, And=May)
      [days={fill=red, text=black, rounded corners, text depth=0pt},
        day text=$\heartsuit$];
\end{tikzpicture}
\end{document}

Output

enter image description here

5
  • Very powerful. Thanks a lot. The earlier solution worked, too, but this brings a lot more flexibility.
    – healyp
    Oct 28, 2013 at 11:06
  • What is the name of the node (and={Jan}{first=Monday})? I'd like to draw a line from its centre to the centre of the last Monday on December using \draw ( )--( );.
    – Sigur
    Feb 12, 2016 at 17:26
  • 1
    Extremely helpful code, thank you. Feel like this should be included in pgfcalendar!
    – abroekhof
    Feb 15, 2022 at 15:00
  • @abroekhof I've updated my answer and exported the code to a new library. Jul 22, 2022 at 23:49
  • 1
    @Sigur I somehow missed your comment even when I've updated the answer last year. Just for completeness (and to maybe help future visitors): You can name a \calendar similar to how a matrix can be named. Then every day node will be available as (<calendar name>-<year>-<month>-<day>) – e.g. mycal-2023-09-21 – (unless default settings are changed). Of course, you can always overwrite this with a conditional: if (<cond>) [days={name=Foo, alias=Bar}]. Sep 21, 2023 at 11:28

You must log in to answer this question.

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