2

I'm trying to create a monthly calendar using Tikz.

I am using this template. Everything is working fine, except the fact that I would like to be able to have the numbers of the days from the previous and next months which are in the displayed weeks, like in this example (Figure 7.7). I see that it is possible with PGF. Can I do it with Tikz calendar as well?

2 Answers 2

3

In a very simply way with tikZ this can be done using the dates key and if (<test date>) [<style>] path of the \calendar command. Both are well documented in the PGFmanual. There can be more clever solutions. With this solution for example with the following code:

\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calendar}
\newcommand{\calOfTheMonth}[4]{%
\calendar [dates=2021-0#1-01+-#2 to 2021-0#1-last+#3,week list,month yshift=0pt]
if (between=2021-0#1-01+-#2 and 2021-0#1-01+-1) [gray]
if (between=2021-0#1-last+1 and 2021-0#1-last+#3) [gray];
\node[above=3ex,anchor=west] {#4};}
\begin{document}
%Explanation of the \calOfTheMonth macro
% \calOfTheMonth{n. of the month}{days to add before}{days to add after}{name of the month}
\tikz
\matrix{
\calOfTheMonth{1}{4}{0}{January}\\
\calOfTheMonth{2}{0}{0}{February}\\
\calOfTheMonth{3}{0}{4}{March}\\
\calOfTheMonth{4}{3}{2}{April}\\
\calOfTheMonth{5}{5}{6}{May}\\
\calOfTheMonth{6}{1}{4}{June}\\
\calOfTheMonth{7}{3}{1}{July}\\
\calOfTheMonth{8}{6}{5}{August}\\
\calOfTheMonth{9}{2}{3}{September}\\
\calOfTheMonth{10}{4}{0}{October}\\
\calOfTheMonth{11}{0}{5}{November}\\
\calOfTheMonth{12}{2}{2}{December}\\
};
\end{document}

calendar with full weeks

4
  • Thanks! Before writing the question, I had tried to set the dates, but I was forgotting month yshift=0... However, is it possible to build a macro to automatically calculate the numbers of days to add before and after?
    – jd6
    Dec 29, 2020 at 15:08
  • 1
    @jd6 In these days I have worked on a calendar if you are interested this is the result
    – vi pa
    Jan 1, 2021 at 15:37
  • Thank you for sharing! The result is very nice! I didn't know the wls format to get the moon phases and the saints. What software do you use to run a wls file?
    – jd6
    Jan 1, 2021 at 18:04
  • 1
    It's wolfram engine for developer with WolframScript. It's a kind of free version of Mathematica, very powerful for manipulate string of text. I've imported the moon from a NASA web site and the saint of the day from a page of Wikipedia.
    – vi pa
    Jan 1, 2021 at 18:12
3

With the ext.calendar-plus library of my tikz-ext package we can hack something more automatic together:

This approach uses the following conditions that were first implemented in another answer of mine but are now part of the library mentioned.

  • week of month = <value>:
    Returns true if the current date is in the <value>th week of the month.

    For week of month = 1 this is basically equal to between = <month>-01 and <month>-07 but doesn't do as much calculations.

  • week of month' = <value>:
    Returns true if the current date is in the <value>th last week of the month.

  • and = <list of conditions>:
    Returns true if all conditions in the list evaluate to true

It also uses two new conditions that were created for this answer but are also now part of the library:

  • calendar week of month = <value>
    Returns true if the current date is in the <value>th calendar week of the month.
  • calendar week of month' = <value>
    Returns true if the current date is in the <value>th last calendar week of the month.

They both use the current day and the current weekday to calculate the number of calendar week and compare it with the given value.

The calendar week of month' condition uses the calendar week of month key but reverses the numbers before it's called.


If we now and the two conditions

  • week of month = 1 (i.e. first seven days of the week) and
  • calendar week of month = 2 (i.e. the seven days in the second calendar week)

we found those days and week days where we'll want to have another day of the previous week added to our calendar.

The same applies for the end of the week with

  • week of month' = 1 (i.e. the last seven days of the week) and
  • calendar week of month' = 2.

If these conditions apply we directly execute style add day from week before or add day from week after. (With “directly” I mean that they're executed even before the actual current day is called – it might be more logical to add this code to execute at end day scope.)

Since this is executed as part of the ifs it might inherit settings that originally apply to the actual current day. However, if we add our ifs as early as possible, we might be in the clear.

The add day from week before and add day from week after simulate time travel to the week before/after the currently processed day.

The \pgftransformyshift is obviously dependent of the actual style of the calendar, it might be better to put this into the add day from week … style so that this code can be better reused for other calendar styles.

Code

\documentclass[border=3mm,tikz]{standalone}
\usetikzlibrary{ext.calendar-plus}
\makeatletter
\tikzset{
  add day from week before/.default=, add day from week after/.default=,
  add day from week before/.code={%
    \begingroup % shift whole calendar 7 days in the past
      \advance\pgfcalendarcurrentjulian by -7
      \pgfcalendarjuliantodate{\pgfcalendarcurrentjulian}{\pgfcalendarcurrentyear}{\pgfcalendarcurrentmonth}{\pgfcalendarcurrentday}%
      \pgfcalendarjuliantoweekday{\pgfcalendarcurrentjulian}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweekday{\the\pgfutil@tempcntb}%
      \pgfcalendarjulianyeartoweek{\pgfcalendarcurrentjulian}{\pgfcalendarcurrentyear}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweek{\ifnum\pgfutil@tempcntb<10 0\fi\the\pgfutil@tempcntb}%
      \pgftransformyshift{\pgfkeysvalueof{/tikz/day yshift}}%
      \tikzset{every day from week before/.try,#1}%
      \tikzdaycode
    \endgroup},
  add day from week after/.code={%
    \begingroup % shift whole calendar 7 days in the future
      \advance\pgfcalendarcurrentjulian by +7
      \pgfcalendarjuliantodate{\pgfcalendarcurrentjulian}{\pgfcalendarcurrentyear}{\pgfcalendarcurrentmonth}{\pgfcalendarcurrentday}%
      \pgfcalendarjuliantoweekday{\pgfcalendarcurrentjulian}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweekday{\the\pgfutil@tempcntb}%
      \pgfcalendarjulianyeartoweek{\pgfcalendarcurrentjulian}{\pgfcalendarcurrentyear}{\pgfutil@tempcntb}%
      \edef\pgfcalendarcurrentweek{\ifnum\pgfutil@tempcntb<10 0\fi\the\pgfutil@tempcntb}%
      \pgftransformyshift{-(\pgfkeysvalueof{/tikz/day yshift})}%
      \tikzset{every day from week after/.try,#1}%
      \tikzdaycode
    \endgroup}}
\makeatother
\begin{document}
\sffamily
\tikz\calendar[
  dates=2022-01-01 to 2022-03-31, week list, month label above centered,
  % as early as possible
  if = {(and = {week of month = 1, calendar week of month = 2}) [add day from week before]},
  if = {(and = {week of month'= 1, calendar week of month'= 2}) [add day from week after]},
  every day from week before/.style=gray,
  every day from week after/.style={gray,if=(Sunday)[red!25!gray]},
] if (Sunday) [red];
\end{document}

Output

enter image description here

1
  • Nice solution, thanks for your detailed explanation and code!
    – jd6
    Jan 30 at 1:05

You must log in to answer this question.

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