3

Modified LaTeX template:

% DIN-A4 doublesided year calendar
% Author: Robert Krause
% License : Creative Commons attribution license
% Submitted to TeXample.net on 13 July 2012
\documentclass[landscape,a4paper, 10pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz}           % Use the calendar.sty style

\usepackage{translator} % German Month and Day names
\usepackage{fancyhdr}       % header and footer
\usepackage{fix-cm}     % Large year in header

\usepackage[landscape, headheight = 2cm, margin=.5cm,
  top = 3.2cm, nofoot]{geometry}
\usetikzlibrary{calc}
\usetikzlibrary{calendar}
\renewcommand*\familydefault{\sfdefault}

% User defined
\def\year{2016}
\def\nextyear{2017}
% Names of Holidays are inserted by employing this macro
\def\termin#1#2{
  \node [anchor=north west, text width= 3.4cm] at
    ($(cal-#1.north west)+(3em, 0em)$) {\tiny{#2}};
}

%Header
\renewcommand{\headrulewidth}{0.0pt}
\setlength{\headheight}{3ex}
\chead{
  %\fontsize{60}{70}\selectfont\textbf{\year}
  \Large\textbf{Cleaning Plan}\hfill
}
%Footer
%\cfoot{\footnotesize\texttt{http://www.texample.net/}}
\pagenumbering{gobble}

% === Macro that returns a name if given a number from 0 to 29, "Error!" otherwise
\newcommand{\Person}[1]{%
\ifcase#1
Bryant Romans \or
Latricia Stoneman \or
Wilmer Lytton \or 
Tommie Lenahan \or 
Antonio Hoggard \or 
Edward Lanctot \or 
Chassidy Hyndman \or 
Marianela Wojciechowski \or 
Edna Kreitzer \or 
Harrison Cruze \or 
Marna Meloy \or 
Georgene Joly \or 
Ken Denley \or 
William Loeffler \or 
Young Spinelli \or 
Glendora Bruss \or 
Kraig Calloway \or 
Chantal Callejas \or 
Eleni Graziani \or 
Ilene Crumpler \or 
Ali Valliere \or 
Sonya Barlett \or 
Frederick Delacruz \or 
Kayce Foti \or 
Orval Kirchner \or 
Corrinne Cahoon \or 
Modesto Mulloy \or 
Alessandra Rodenberger \or 
Bernita Redman \or 
Iola Eudy \else
Error! \fi
}

\xdef\cleanerID{18}

\begin{document}
\pagestyle{fancy}
\begin{center}
\begin{tikzpicture}[every day/.style={anchor = north}]
\calendar[
  dates=\year-09-01 to \nextyear-02-28,
  name=cal,
  day yshift = 3em,
  day code=
  { %=== Define macro that holds cleaners name on cleaning days, empty otherwise
    \ifdate{Monday,Wednesday,Saturday}%
    {   \ifdate{between=\year-11-18 and \year-12-09, at least=\nextyear-01-03}
        {   \xdef\InsertName{\Person{\cleanerID}}
            \pgfmathtruncatemacro{\newCleanerID}{mod(\cleanerID+1,30)}
                \xdef\cleanerID{\newCleanerID}
            }
            {   \xdef\InsertName{}
            }
    }
    {   \xdef\InsertName{}
    } 
    \ifdate{equals=\year-11-21}
    {   \xdef\InsertName{Iola Eudy}
        \tikzset{every day/.style={fill=cyan!50!blue!50}}       
    }{}
    \ifdate{equals=\nextyear-01-06}
    {   \xdef\InsertName{Ilene Crumpler}
        \tikzset{every day/.style={fill=cyan!50!blue!50}}       
    }{}
    \node[name=\pgfcalendarsuggestedname,every day,shape=rectangle,
    minimum height= .53cm, text width = 4.4cm, draw = gray]{\tikzdaytext};
    %=== Insert the  cleaners name here
    \draw (-1.8cm, -.1ex) node[anchor = west]{\footnotesize%
      \pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday} \InsertName
      };
  },
  execute before day scope=
  {
    \ifdate{day of month=1}
    {
      % Shift right
      \pgftransformxshift{4.8cm}
      % Print month name 
      \draw (0,0)node [shape=rectangle, minimum height= .53cm,
        text width = 4.4cm, fill = black, text= white, draw = black, text centered]
        {\textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth} \pgfcalendarcurrentyear}
        };
    }{}
    \ifdate{workday}
    {
      % normal days are white
      \tikzset{every day/.style={fill=white}}
    }{}
    % Saturdays and half holidays (Christma's and New year's eve)
    \ifdate{Saturday}{\tikzset{every day/.style={fill=red!10}}}{}
    % Sundays and full holidays
    \ifdate{Sunday}{\tikzset{every day/.style={fill=red!20}}}{}
  },
 execute at begin day scope=
  {
    % each day is shifted down according to the day of month
    \pgftransformyshift{-.53*\pgfcalendarcurrentday cm}
  }
];
\end{tikzpicture}
% Repeat the whole thing for the second page
%\pagebreak

\begin{tikzpicture}[every day/.style={anchor = north}]
\calendar[dates=\nextyear-05-01 to \nextyear-10-31,
  name=cal,
  day yshift = 3em,
  day code=
  { %=== Define macro that holds cleaners name on cleaning days, empty otherwise
    \ifdate{Monday,Wednesday,Saturday}%
    {   \ifdate{at least=\nextyear-01-03}
        {   \xdef\InsertName{\Person{\cleanerID}}
            \pgfmathtruncatemacro{\newCleanerID}{mod(\cleanerID+1,30)}
                \xdef\cleanerID{\newCleanerID}
            }
            {   \xdef\InsertName{}
            }
    }
    {   \xdef\InsertName{}
    }   
    \node[name=\pgfcalendarsuggestedname,every day,shape=rectangle,
    minimum height= .53cm, text width = 4.4cm, draw = gray]{\tikzdaytext};
    %=== Insert the  cleaners name here
    \draw (-1.8cm, -.1ex) node[anchor = west]{\footnotesize%
      \pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday} \InsertName
      };
  },
  execute before day scope=
  {
    \ifdate{day of month=1} {
    % Shift right
    \pgftransformxshift{4.8cm}
    % Print month name 
    \draw (0,0)node [shape=rectangle, minimum height= .53cm, 
      text width = 4.4cm, fill = black, text= white, draw = black, text centered]
    {
      \textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth} \pgfcalendarcurrentyear}
    };
  }{}
  \ifdate{workday}
  {
    \tikzset{every day/.style={fill=white}}
  }{}
  % Saturdays and half holidays (Christma's and New year's eve)
  \ifdate{Saturday}{\tikzset{every day/.style={fill=red!10}}}{}
  % Sundays and full holidays
  \ifdate{Sunday}{\tikzset{every day/.style={fill=red!20}}}{}
  },
  execute at begin day scope=
  {
   % Each day is shifted down according to the day of month
    \pgftransformyshift{-.53*\pgfcalendarcurrentday cm}
  }
];
\end{tikzpicture}
\end{center}
\end{document}

Changed

I've changed following lines:

% User defined
\def\year{2015}
\def\nextyear{2016}

dates=\year-11-01 to \nextyear-04-30,

Problems

I'm a flight assistant. Following I don't know how to change:

  • We are 15 people at my team. It's always Mondays and Thursdays. Flight assistant (Number 13) doesn't have to clean the toilets at all --- so I need a counting like [... 11, 12, 14, 15, 1 ...]. The toilet cleaning starts with number the 5th of September.

  • Vacation: the 21st of December - 23rd of January and the 26th of May - the 1st of September. The calendar should break there.

Problem solving

Changing the number

\pgfmathtruncatemacro{\newCleanerID}{mod(\cleanerID+1,30)}

I would change it to following:

\pgfmathtruncatemacro{\newCleanerID}{mod(\cleanerID+1,15)}

I hope you will help me :-)

NB! Is it possible to define the start / stop of the calendar / cleaning at the top; and is it possible to define the vacation at the top as well? So instead of digging through the code?

  • Welcome! Why are you telling the class you are using German but telling Babel you are using US English? – cfr Sep 4 '16 at 19:27
  • Why do you need to include number 13 at all i.e. in the \Person list if number 13 should never be included in the rota? Why not just include the names of the 14 who do have to do the cleaning? – cfr Sep 4 '16 at 19:53
  • Never use \def in LaTeX unless you know it is necessary, you know it is safe and you understand the risks. Here, you are overwriting an existing macro. Are you sure that is OK? Are you sure you don't need it? Are you sure it won't have unwanted side-effects in unexpected places? – cfr Sep 4 '16 at 20:21
4

I think it is a mistake to want to define things at the top. That would mean the body of the document contained multiple copies of the static configuration, while the preamble contained one set of customisations and the body included an additional set for each calendar after the first.

Duplicating the static code makes it harder to customise and maintain.

I recommend putting the static code into the preamble and defining a simple command to produce each calendar.

\rgcalendar[<tikz keys to customise>]

takes a single, optional argument and produces a calendar. Additional keys are provided to ease customisation.

  • rg start date=<YYYY>-<MM>-<DD> for the start date
  • rg end date=<YYYY>-<MM>-<DD> for the end date
  • rg cleaning dates=<specification using the calendar syntax> for the period(s) of cleaning
  • rg cal colour=<colour> for the highlighting colour used at weekends, unmixed with white
  • rg cal draw=<colour> for the colour used to draw the boxes around the days
  • rg cal fill=<colour> for the colour used to fill the non-weekend days

I've also simplified the code a bit so that it does not take quite so long to compile. I've removed or renamed macros which overwrote existing ones and used LaTeX macros for macro definitions whenever possible.

I've used a counter rather than a macro to track the count of cleaners and another counter to give the calendars unique names.

Defaults are set to produce the first calendar described in the question, so \rgcalendar without the optional argument will work there. Subsequent calendars obviously need to be adapted appropriately.

The upshot of all this is that

\rgcalendar
\rgcalendar[%
  rg start date=2017-03-01,
  rg end date=2017-08-31,
  rg cleaning dates={between=\rgcalyear-01-23 and \rgcalyear-05-26},
  rg cal colour=blue,
]
\rgcalendar[%
  rg start date=2017-09-01,
  rg end date=2018-02-28,
  rg cleaning dates={between=\rgcalyear-09-01 and \rgcalyear-12-21, at least=\rgnextcalyear-01-23},
  rg cal colour=violet,
]

produces

3 calendars

% DIN-A4 doublesided year calendar
% Author: Robert Krause
% License : Creative Commons attribution license
% Submitted to TeXample.net on 13 July 2012

% Modifications by cfr 4 September 2016

\documentclass[landscape, a4paper, american, 10pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz}           % Use the calendar.sty style
\usepackage{fancyhdr}       % header and footer
\usepackage[sf={lining,proportional},tt={lining,monowidth},rm={lining,oldstyle}]{cfr-lm}
\usepackage[landscape, headheight = 2cm, margin=.5cm, top = 3.2cm, nofoot, headheight=3ex]{geometry}% don't set layout dimensions manually if using geometry - it won't know about them when it calculates everything!
\usetikzlibrary{calc,calendar}
\renewcommand*\familydefault{\sfdefault}
%Header
\renewcommand{\headrulewidth}{0pt}
\fancyhf{}
\lhead{%
  \Large\textbf{Cleaning Plan}%
}
% === Macro that returns a name if given a number from 0 to 15, "Error!" otherwise
\newcommand*{\Person}[1]{%
  \ifcase#1
  person 1 \or
  person 2 \or
  person 3 \or
  person 4 \or
  person 5 \or
  person 6 \or
  person 7 \or
  person 8 \or
  person 9 \or
  person 10 \or
  person 11 \or
  person 12 \or
  person 13 \or
  person 14 \or
  person 15 \else
  Error! \fi
}
\newcounter{cleanerID}
\setcounter{cleanerID}{0}
\newcounter{rgcal}
\setcounter{rgcal}{0}
\newcommand*\InsertName{}
\pagestyle{fancy}
\tikzset{%
  rg cal/.code={%
    \stepcounter{rgcal}%
    \tikzset{%
      every day/.style={anchor=center, minimum height=.53cm, text width=4.4cm, fill=rgcalfill, draw=rgcaldraw},
      every month/.style={minimum height=.53cm, text width=4.4cm, fill=black, text=white, draw=black, text centered, font=\bfseries},
      name=rgcal\thergcal,
      execute before day scope={%
        \ifdate{day of month=1}
        {% Shift right
          \pgftransformxshift{4.8cm}%
          % Print month name
          \node [every month] {\pgfcalendarmonthname{\pgfcalendarcurrentmonth} \pgfcalendarcurrentyear};
        }{}%
      },
      execute at begin day scope=
      {% each day is shifted down according to the day of month
        \pgftransformyshift{-.53*\pgfcalendarcurrentday cm}%
        \ifdate{Sunday}{%
          \tikzset{rg cal fill=rgcalcol!30}%
        }{%
          \ifdate{Saturday}{%
            \tikzset{rg cal fill=rgcalcol!20}%
          }{}%
        }%
      },
      dates=\rgstartdate{} to \rgenddate,
      #1,
    }%
  },
  rg cal fill/.code={%
    \colorlet{rgcalfill}{#1}%
  },
  rg cal draw/.code={%
    \colorlet{rgcaldraw}{#1}%
  },
  rg cal colour/.code={%
    \colorlet{rgcalcol}{#1}%
  },
  rg cleaning dates/.style={%
    day code={%=== Define macro that holds cleaners name on cleaning days, empty otherwise
      \ifdate{Monday,Thursday}%
      {%
        \ifdate{#1}%between=\calyear-09-05 and \calyear-12-21, at least=\calnextyear-01-23}
        {%
          \ifnum\thecleanerID=12\stepcounter{cleanerID}\fi
          \edef\InsertName{\Person{\thecleanerID}}%
          \stepcounter{cleanerID}%
          \ifnum\thecleanerID=15\setcounter{cleanerID}{0}\fi
        }{}%
      }{}%
      \path node [name=\pgfcalendarsuggestedname, every day] {\tikzdaytext};
      %=== Insert the  cleaners name here
      \node at ([xshift=6mm]\pgfcalendarsuggestedname.base west) [anchor=base west, font=\footnotesize]{\pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday} \InsertName};
    },
  },
  rg start date/.store in=\rgstartdate,
  rg end date/.store in=\rgenddate,
  rg cal year/.store in=\rgcalyear,
  rg next cal year/.store in=\rgnextcalyear,
  rg year/.style args={#1-#2-#3}{%
    /tikz/rg cal year=#1,
  },
  rg next year/.style args={#1-#2-#3}{%
    /tikz/rg next cal year=#1,
  },
  rg start date/.forward to=/tikz/rg year,
  rg end date/.forward to=/tikz/rg next year,
  rg cal draw=gray,
  rg cal colour=red,
  rg cal fill=white,
  rg cleaning dates={between=\rgcalyear-09-05 and \rgcalyear-12-21, at least=\rgnextcalyear-01-23},
  rg start date=2016-09-01,
  rg end date=2017-02-28,
}
\newcommand*\rgcalendar[1][]{%
  \clearpage
  \tikzset{#1}%
  \tikz{\calendar [rg cal];}%
  \clearpage
}

\begin{document}
\centering
\rgcalendar
\rgcalendar[%
  rg start date=2017-03-01,
  rg end date=2017-08-31,
  rg cleaning dates={between=\rgcalyear-01-23 and \rgcalyear-05-26},
  rg cal colour=blue,
]
\rgcalendar[%
  rg start date=2017-09-01,
  rg end date=2018-02-28,
  rg cleaning dates={between=\rgcalyear-09-01 and \rgcalyear-12-21, at least=\rgnextcalyear-01-23},
  rg cal colour=violet,
]
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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