%
% This LaTeX file creates a calendar of all weeks in a person's lifetime,
% similar to the life calendar created by Tim Urban in his blog:
% <http://waitbutwhy.com/2014/05/life-weeks.html>
%
% This calendar correctly handles leap years, weekdays and calendar years.
% 
% Each week takes 5mm x 5mm (shown as rectangle of 4mm x 4mm), so at most 
% 82 years fit onto a A3 page of paper.
%
% To create a PDF, manage to install required LaTeX packages and run:
%
% $ pdflatex calendar.tex
%
\documentclass[a3paper,12pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{backgrounds}
\usepackage{xcolor}
\usepackage{calc}

\usepackage{datenumber}
\newcounter{birthday}
\newcounter{firstday}
\newcounter{firstweek}
\newcounter{daysleft}
\newcounter{weeksleft}
\newcounter{tmp}

% expected life span in years
\newcommand{\firstyear}{0}
\newcommand{\lastyear}{81}

% birthday, date format: year, month, day
\setmydatenumber{birthday}{1990}{1}{1}

% page and font layout
\usepackage[left=0mm,top=3mm,bottom=0mm,right=0mm,nohead,nofoot]{geometry}
\setlength{\parindent}{0pt}
\renewcommand{\familydefault}{\sfdefault} 

\tikzstyle{week}=[
    draw, shape=rectangle,
    minimum width=4mm, minimum height=4mm
]

\tikzset{partial/.style n args={1}{
    week, draw=none,
    append after command={
        [shorten <= -0.5\pgflinewidth]
        ($(\tikzlastnode.north west)!#1/7!(\tikzlastnode.north east)$)
          edge (\tikzlastnode.north west) 
        (\tikzlastnode.north west) 
          edge (\tikzlastnode.south west)            
        (\tikzlastnode.south west) edge
        ($(\tikzlastnode.south west)!#1/7!(\tikzlastnode.south east)$)
    }
}
}

\begin{document}
\thispagestyle{empty}
\begin{center}
\begin{tikzpicture}

\setdatebynumber{\thebirthday}
\newcounter{birthdaymonth}\setcounter{birthdaymonth}{\thedatemonth}
\newcounter{birthdayday}\setcounter{birthdayday}{\thedateday}

\node[anchor=south east,yshift=1mm] at (0,0) {\scriptsize age};

\foreach \age in {\firstyear,...,\lastyear} {

  % left: year of age
  \node[anchor=east] at (0,-5mm*\age) {\age};
  
  % days counter at first day of this year of life
  \setcounter{firstday}{\thedatenumber}

  % first week
  \ifnum\value{datedayname}>1
     % partial week
     \setcounter{firstweek}{\the\numexpr8-\value{datedayname}\relax}
     \node[rotate=180,partial=\thefirstweek] at (5mm,-5mm*\age) {};
  \else
     % full week (starting at monday)
     \setcounter{firstweek}{7}
     \node[week] at (5mm,-5mm*\age) {};
  \fi

  % skip to the day before next birthday
  \addtocounter{dateyear}{1}
  \setdatenumber{\thedateyear}{\thebirthdaymonth}{\thebirthdayday}
  \prevdate

  % number of days in this year of life (358...365)
  \setcounter{daysleft}{\thedatenumber}
  \addtocounter{daysleft}{-\thefirstday}
  \addtocounter{daysleft}{-\thefirstweek}
  \addtocounter{daysleft}{1}

  % full weeks left in this year of life (51...52)
  \pgfmathparse{int(floor(\thedaysleft/7))}
  \setcounter{weeksleft}{\pgfmathresult}

  % days left in the last week (0...6)
  \addtocounter{daysleft}{-7*\theweeksleft}
  \ifnum\value{daysleft}>0
     \node[partial=\thedaysleft] at (5mm*\theweeksleft+5mm,-5mm*\age) {};
  \fi

  \pgfmathsetlengthmacro{\endofyear}{5mm*\theweeksleft+2.5mm+5mm*\thedaysleft/7}

  % end of year
  \setcounter{tmp}{\thedatenumber}

  \setdatenumber{\thedateyear}{1}{1}
  \setcounter{daysleft}{\thedatenumber}
  \addtocounter{daysleft}{-\thefirstday}
  \addtocounter{daysleft}{1}

  %\node[color=blue] at (0,-5mm*\age) {\thedaysleft};
  \pgfmathsetlengthmacro{\newyear}{2.5mm+5mm/7*\thedaysleft-5mm/7*\thefirstweek}

  \pgfmathsetlengthmacro{\startofyear}{7.5mm-\thefirstweek*5mm/7}

  %\draw[thick,color=red] (\endofyear,-5mm*\age+2.5mm) to +(0,-5mm);
  %\draw[thick,color=blue] (\startofyear,-5mm*\age+2.5mm) to +(0,-5mm);
  %\draw[thick,color=green] (\newyear,-5mm*\age+2.5mm) to +(0,-5mm);

  % draw full weeks
  \foreach \week in {2,...,\theweeksleft}
    \node[week] at (5mm*\week,-5mm*\age) {};

  % right: calendar year at the day before next birthday
  \setdatebynumber{\thetmp}
  \ifodd\thedateyear
    \begin{scope}[on background layer]
      \path[fill=gray!20] 
        (\startofyear,-5mm*\age+2.5mm) rectangle (\newyear,-5mm*\age-2.5mm); 
    \end{scope}
  \else
    \begin{scope}[on background layer]
      \path[fill=gray!20] 
        (\newyear,-5mm*\age-2.5mm) rectangle (\endofyear,-5mm*\age+2.5mm);
    \end{scope}
    \node[anchor=west] at (52.5*5mm,-5mm*\age) {\thedateyear};
  \fi

  % skip to next birthday
  \nextdate
  \setdatenumber{\thedateyear}{\thebirthdaymonth}{\thebirthdayday}
}

\end{tikzpicture}
\end{center}
\end{document}
