add tag
निरंजन
I want to programmatically generate a printable diary. For that I am using for loop. See the following code -


\documentclass[a5paper]{book}
\usepackage[pass]{geometry}
\usepackage{forloop}
\usepackage{xcolor}
\newcommand{\printmonth}[4]{
\newcounter{#1}
\forloop{#1}{1}{\value{#1}<#3}{
\begin{minipage}[t][0.5\textheight]{\textwidth}
\hfill #2\ #4, 2021
\end{minipage}
}
\pagebreak
}
\textheight=450pt
\pagenumbering{gobble}
\voffset=-0.5in

\begin{document}
\printmonth{jan}{\thejan}{32}{January}\clearpage\pagebreak
\printmonth{feb}{\thefeb}{29}{February}\clearpage\pagebreak
\printmonth{mar}{\themar}{32}{March}\clearpage\pagebreak
\printmonth{apr}{\theapr}{31}{April}\clearpage\pagebreak
\printmonth{may}{\themay}{32}{May}\clearpage\pagebreak
\printmonth{june}{\thejune}{31}{June}\clearpage\pagebreak
\printmonth{july}{\thejuly}{32}{July}\clearpage\pagebreak
\printmonth{aug}{\theaug}{32}{August}\clearpage\pagebreak
\printmonth{sep}{\thesep}{31}{September}\clearpage\pagebreak
\printmonth{oct}{\theoct}{32}{October}\clearpage\pagebreak
\printmonth{nov}{\thenov}{31}{November}\clearpage\pagebreak
\printmonth{dec}{\thedec}{32}{December}
\ifthenelse{\value{june}=2}{
\fcolorbox{yellow}{blue!20}{
\begin{minipage}[t][0.5\textheight]{\textwidth}
\hfill BIRTHDAY
\end{minipage}
}
}
{}
\end{document}


This gives me a diary, but now I want to mark my birthday differently by having a colored minipage. (Guidelines found [here][1].) but the code with command \ifthenelse generates an empty minipage on the actual date and also gives the output from the for loop. I require a command which will have a date as its argument and change the for loop output of that specific minipage. Something similar to [this][2] from tikzlibrary calendar, but I couldn't extract dates from that library in a variable. I want something like follows -


\event{02-06-2021}{BIRTHDAY}{blue!20}


Also a macro which would add notes on a particular date would be amazing. For those who want to write directly on LaTeX without printing the diary eg.


\daynote{02-06-2021}{This is some text which is supposed to be printed on the minipage titled 2 June, 2021}

PS - Please suggest improvements in the code. I must have done things in a novice way. I want to make an elegant diary out of this code.

This question can also be found on TeX.SE [here][3]

[1]: https://tex.stackexchange.com/a/196206/174620
[2]: https://tex.stackexchange.com/a/102456/174620
[3]: https://tex.stackexchange.com/questions/553390/making-a-diary-with-latex
Top Answer
marmot
You can use the pgfcalendar package, which seems to precisely match your requirements. It has a huge set of data built in. For instance, you can just specify a range of dates and it would "know" if a certain day is a Sunday.

Instead of the minipages I would use tcolorboxes. Apart from convenience it has the advantage that one can find a straightforward way to implement the \event command via the /.try key handler. To understand what that means, let us look at this short code:


\documentclass[a5paper]{book}
\usepackage[pass]{geometry}
\pagenumbering{gobble}
\usepackage{tcolorbox}
\usepackage{pgfcalendar}
\newcommand\event[2]{\tcbset{#1/.style={#2}}}
\newcommand{\printday}[1][]{\ifnum\pgfcalendarcurrentday=1\relax
\clearpage%<- to make sure that every month starts at the top of the page
\fi
\begin{tcolorbox}[height=0.45\textheight,
colback=white,colframe=white,arc=0pt,%<- general appearance
\pgfcalendarcurrentday-\pgfcalendarcurrentmonth/.try%<- specific appearance
]
\hfill \pgfcalendarcurrentday\ \pgfcalendarshorthand mt,
\pgfcalendarcurrentyear\par
\end{tcolorbox}\par\vfill
}
\begin{document}
\event{02-06}{colback=blue!20,before upper=Birthday}
\pgfcalendar{cal}{2021-5-27}{2021-6-06}{\printday}
\end{document}


![ani.gif](/image?hash=721de9d5a947354bf2c85b7221fc55e6b9d654b5951ca8f0061ea4303965222d)

The diary will be created with \pgfcalendar{cal}{2021-5-27}{2021-6-06}{\printday}, where 2021-5-27 is the start date and 2021-6-06 the end date. The command \event{02-06}{colback=blue!20,before upper=Birthday} defines a style that will be applied at this date, i.e. June 2nd. In this example, the day has a blue background, and the word "Birthday" gets injected via before upper. The /.try key handler is instrumental for that to work. For every day it looks if a style \pgfcalendarcurrentday-\pgfcalendarcurrentmonth exists, and if so, it applies the style. That way you can create an arbitrary number of events.

There are many ways to generalize this. One can add more /.try styles to make things specific to months, say. One can also test if a given day is a Sunday, say, and so on. Here is an example that marries the above to the vaieous checks you can find in section **90.1.2 Checking Dates** of pgfmanual v3.1.5.


\documentclass[a5paper]{book}
\usepackage[pass]{geometry}
\pagenumbering{gobble}
\usepackage{tcolorbox}
\usepackage{pgfcalendar}
\pgfkeys{/pgf/calendar/diary checks/.code={}}
\newcommand\event[2]{\pgfkeys{/pgf/calendar/diary checks/.append code={%
\pgfcalendarifdate{\noexpand\pgfcalendarcurrentyear-\noexpand\pgfcalendarcurrentmonth-\noexpand\pgfcalendarcurrentday}{#1}{%
\tcbset{diary day-\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday/.style={#2}}}{}%
}}}
\tcbset{diary day/.style={height=0.45\textheight,
colback=white,colframe=white,arc=0pt,%<- general appearance
diary day-\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday/.try%
% specific appearance
}}
\newcommand{\printday}[1][]{\pgfkeys{/pgf/calendar/diary checks}%
\ifnum\pgfcalendarcurrentday=1\relax
\clearpage%<- to make sure that every month starts at the top of the page
\fi
\begin{tcolorbox}[diary day]
\hfill \pgfcalendarcurrentday\ \pgfcalendarshorthand mt,
\pgfcalendarcurrentyear\par
\end{tcolorbox}\par\vfill
}
\newenvironment{diary}[3][]{\begingroup\edef\startdate{#2}%
\edef\enddate{#3}}{%
\pgfcalendar{cal}{\startdate}{\enddate}{\printday}\endgroup}
\begin{document}
\begin{diary}{2021-5-27}{2021-6-06}
\event{equals=06-02}{colback=blue!20,before upper=Birthday}
\event{Sunday}{colback=red!20}
\end{diary}
\end{document}


![ani.gif](/image?hash=862ac55595384289ef1d91ac055b820c2c70b6c7048a9b988ad91cca07d9da25)

The whole diary now is generated by the diary environment, which takes two arguments, the start and end dates. As you can see, now the Sundays become red. In order to mark the birthday, we had to change the syntax to \event{equals=06-02}{...} in order to become what is supported by the pgfcalendar package.

You can either use the translator package or install your own macros to customize the language/output.


\documentclass[a5paper]{book}
\usepackage[pass]{geometry}
\pagenumbering{gobble}
\usepackage{tcolorbox}
\usepackage{pgfcalendar}
\pgfkeys{/pgf/calendar/diary checks/.code={}}
\newcommand\event[2]{\pgfkeys{/pgf/calendar/diary checks/.append code={%
\pgfcalendarifdate{\noexpand\pgfcalendarcurrentyear-\noexpand\pgfcalendarcurrentmonth-\noexpand\pgfcalendarcurrentday}{#1}{%
\tcbset{diary day-\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday/.style={#2}}}{}%
}}}
\newcommand\daynote[2]{\event{equals=#1}{after upper=#2}}
\tcbset{diary day/.style={height=0.45\textheight,
colback=white,colframe=white,arc=0pt,%<- general appearance
diary day-\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday/.try%
% specific appearance
}}
\newcommand{\printday}[1][]{\pgfkeys{/pgf/calendar/diary checks}%
\ifnum\pgfcalendarcurrentday=1\relax
\clearpage%<- to make sure that every month starts at the top of the page
\fi
\begin{tcolorbox}[diary day]
\hfill \myweekdayname{\pgfcalendarcurrentweekday},\ \pgfcalendarcurrentday\ \pgfcalendarshorthand mt,
\pgfcalendarcurrentyear\par
\end{tcolorbox}\par\vfill
}
\newcommand\myweekdayname[1]{\ifcase#1\relax
Marmotday\or Duckday\or Mouseday\or Deerday\or Falconday\or Slothday\or
Squirrelday\fi}
\newenvironment{diary}[3][]{\begingroup\edef\startdate{#2}%
\edef\enddate{#3}}{%
\pgfcalendar{cal}{\startdate}{\enddate}{\printday}\endgroup}
\begin{document}
\begin{diary}{2021-5-27}{2021-6-06}
\event{equals=06-02}{colback=blue!20,before upper=Birthday}
\event{Sunday}{colback=red!20}
\daynote{06-04}{Made a major donation to the marmot recovery foundation.}
\end{diary}
\end{document}


![ani.gif](/image?hash=5af42b57f728a3c1d10ff74a5d26fb47fbf76420da775af97929418acb7a37e8)

If you use \pgfcalendarweekdayname instead of \myweekdayname you get the traditional week days. As you can see, the \daynote command has been added as a variant of the \event command.
Answer #2
joulev
I use expl3 for full programming capacity ;) The commands are self-descriptive.


% arara: pdflatex
\documentclass{article}
\usepackage{expl3}
\setlength\parskip{0pt}
\ExplSyntaxOn
\int_new:N \l_dairy_no_of_days_int
\prop_new:N \l_dairy_entry_prop
\tl_new:N \l_dairy_default_tl
\tl_new:N \l_dairy_tmpa_tl
\tl_new:N \l_dairy_tmpb_tl
% Use something you'd never use in a diary entry
\tl_const:Nn \c_dairy_prop_initial_tl
{ @@@@@@@@@@ }
% Edit this based on whether leap year or not
\intarray_const_from_clist:Nn \c_dairy_day_in_month_intarray
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
\cs_generate_variant:Nn \prop_put:Nnn { Nxn, NxV }

% Initialize the property list
\int_step_variable:nNn {12} \l_dairy_month_tl
{
\int_step_variable:nNn
{ \intarray_item:Nn \c_dairy_day_in_month_intarray { \l_dairy_month_tl } }
\l_dairy_day_tl
{
\prop_put:NxV \l_dairy_entry_prop
{
\int_compare:nNnT { \l_dairy_day_tl } < {10} {0}
\l_dairy_day_tl -
\int_compare:nNnT { \l_dairy_month_tl } < {10} {0}
\l_dairy_month_tl
}
\c_dairy_prop_initial_tl
}
}

% Some functions to modify the property list
\cs_new_protected:Npn \DairySetDefault #1
{ \tl_set:Nn \l_dairy_default_tl {#1} }

\cs_new_protected:Npn \DairySet #1 #2
{ \prop_put:Nnn \l_dairy_entry_prop {#1} {#2} }

% Here comes the main function
\cs_new:Npn \Dairy
{
\int_step_variable:nNn {12} \l_dairy_month_tl
{
\int_step_variable:nNn
{ \intarray_item:Nn \c_dairy_day_in_month_intarray { \l_dairy_month_tl } }
\l_dairy_day_tl
{
\tl_set:Nx \l_dairy_tmpa_tl
{
\int_compare:nNnT { \l_dairy_day_tl } < {10} {0}
\l_dairy_day_tl -
\int_compare:nNnT { \l_dairy_month_tl } < {10} {0}
\l_dairy_month_tl
}
\prop_get:NVN \l_dairy_entry_prop \l_dairy_tmpa_tl \l_dairy_tmpb_tl
\tl_if_eq:NNT \l_dairy_tmpb_tl \c_dairy_prop_initial_tl
{
\prop_put:NVV \l_dairy_entry_prop \l_dairy_tmpa_tl
\l_dairy_default_tl
}
% The diary is stored at item \l_dairy_tmpa_tl of \l_dairy_entry_prop.
% Do whatever you want with it.
\noindent
\begin{minipage}[t][0.5\textheight]{\textwidth}
\textbf{\l_dairy_tmpa_tl-2021}\par
\prop_get:NVN \l_dairy_entry_prop \l_dairy_tmpa_tl \l_dairy_tmpb_tl
\l_dairy_tmpb_tl
\end{minipage}
\par
}
}
% Uncomment the following line and look at the log file
%\prop_log:N \l_dairy_entry_prop
}
\ExplSyntaxOff
\begin{document}
\DairySetDefault{just a boring day don't even bother}
\DairySet{02-06}{Happy birthday!}
\Dairy
\end{document}


![blob](/image?hash=57872cce3612b3392f9cce18ce664446b44e6c4fb6f9795e669a4ba3fc8cee72)

![blob](/image?hash=52ef18fa481273dfc34c814995ff63f1f2d86e55fd0f2f1fe6eb821630c4d602)


Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.