# pgfgantt: How to display week numbers according to ISO 8601 counting scheme?

In addition to the calendarian month names, I added a calendarian week counter (week 1 up to week 52) into the title of a pgfgantt-chart.

Minimum Working Example (MWE):

\documentclass{standalone}
\usepackage{pgfgantt}

\newcounter{resetWeekNum}
\stepcounter{resetWeekNum}
\newcommand{\resetWeek}{ %
\theresetWeekNum
\stepcounter{resetWeekNum}
\ifnum\theresetWeekNum=53
\setcounter{resetWeekNum}{1}
\else\fi
}

\begin{document}

\setcounter{resetWeekNum}{27}
\ganttset{calendar week text=\scriptsize{\resetWeek{}}}

\begin{ganttchart}
[   time slot format    =   isodate,
x unit              =   2mm,
vgrid               =   true,
]   {2019-07-01}{2021-05-16}

\gantttitlecalendar{year, month=name,week=1 day} \\ % weekday=letter
\ganttbar{WP1}{2019-04-01}{2020-12-27} \\
\ganttbar{WP2}{2019-04-01}{2020-12-31} \\
\ganttbar{WP2}{2019-04-01}{2021-01-03} \\

\end{ganttchart}

\end{document}


Screenshot of the result (year 2019 - 2020):

Screenshot of the result (year 2020 - 2021):

Description of the issue:

While the current week counter works completely fine for years 2019 to 2020 (counting 52 weeks for 2019), there is some small failure from 2020 to 2021 (falsely counting 52 weeks instead of 53 weeks).

The problem:

According to international week counting standard ISO 8601, the first calendarian week of each year is the week that contains the first Thursday of the year. After that, the next counted week starts on Monday (= as the second calendarian week). Therefore: 2019 has 52 weeks while 2020 has 53 weeks.

From Wikipedia:

"ISO 8601 includes the ISO week date system, a numbering system for weeks – each week begins on a Monday and is associated with the year that contains that week's Thursday (so that if a year starts in a long weekend Friday–Sunday, week number one of the year will start after that). For example, week 1 of 2004 (2004W01) ran from Monday, 29 December 2003 to Sunday, 4 January 2004, because its Thursday was 1 January 2004, whereas week 1 of 2005 (2005W01) ran from Monday, 3 January 2005 to Sunday, 9 January 2005, because its Thursday was 6 January 2005 and so the first Thursday of 2005."

The question:

How can I display calendarian week numbers in consideration of the ISO 8601 standard counting scheme?

• To be honest, I do not understand the problem. The weeks are numbered 1, 2, ... The last week of year gets labeled 1 if it overlaps with the next year since then it is week one of the next year. Where precisely do you want to see a 53? – Schrödinger's cat Sep 30 '19 at 16:44
• @Schrödinger'scat: Thanks for the hint! Please see my updated question... Thanks a lot! :-) – Dave Oct 1 '19 at 13:28

I agree with Steven that this may be some sort of an overkill. On the other hand the calendar library has the nice \pgfcalendarifdate built in, so...

\documentclass{standalone}
\usepackage{pgfgantt}
\newif\ifspecialweek
\newcounter{resetWeekNum}
\stepcounter{resetWeekNum}
\newcommand{\resetWeek}{ %
\theresetWeekNum
\stepcounter{resetWeekNum}
\specialweekfalse
\pgfcalendarifdate{31-12-\startyear}{Thursday}{\global\specialweektrue}{}
\pgfcalendarifdate{31-12-\startyear}{Friday}{\global\specialweektrue}{}
\pgfcalendarifdate{31-12-\startyear}{Saturday}{\global\specialweektrue}{}
\pgfcalendarifdate{31-12-\startyear}{Sunday}{\global\specialweektrue}{}
\ifspecialweek
\ifnum\theresetWeekNum=54
\setcounter{resetWeekNum}{1}
\fi
\else
\ifnum\theresetWeekNum=53
\setcounter{resetWeekNum}{1}
\fi
\fi
}

\begin{document}

\setcounter{resetWeekNum}{27}
\ganttset{calendar week text=\scriptsize{\resetWeek}}

\begin{ganttchart}
[   time slot format    =   isodate,
x unit              =   2mm,
vgrid               =   true,
]   {2019-07-01}{2021-05-16}

\gantttitlecalendar{year, month=name,week=1 day} \\ % weekday=letter
\ganttbar{WP1}{2019-04-01}{2020-12-27} \\
\ganttbar{WP2}{2019-04-01}{2020-12-31} \\
\ganttbar{WP2}{2019-04-01}{2021-01-03} \\

\end{ganttchart}

\end{document}


Since the 53-week year happens only occasionally and never in quick succession, I think in this case, it is easier to hardwire 53 weeks for the particular case when \ifnum\startyear=2020 rather than develop an ISO 8601-compliant version. It is the former course which I have done in the MWE.

\documentclass{standalone}
\usepackage{pgfgantt}

\newcounter{resetWeekNum}
\stepcounter{resetWeekNum}
\newcommand{\resetWeek}{ %
\theresetWeekNum
\stepcounter{resetWeekNum}
\ifnum\startyear=2020
\ifnum\theresetWeekNum=54
\setcounter{resetWeekNum}{1}
\else\fi
\else
\ifnum\theresetWeekNum=53
\setcounter{resetWeekNum}{1}
\else\fi
\fi
}

\begin{document}

\setcounter{resetWeekNum}{27}
\ganttset{calendar week text=\scriptsize{\resetWeek{}}}

\begin{ganttchart}
[   time slot format    =   isodate,
x unit              =   2mm,
vgrid               =   true,
]   {2019-07-01}{2021-05-16}

\gantttitlecalendar{year, month=name,week=1 day} \\ % weekday=letter
\ganttbar{WP1}{2019-04-01}{2020-12-27} \\
\ganttbar{WP2}{2019-04-01}{2020-12-31} \\
\ganttbar{WP2}{2019-04-01}{2021-01-03} \\

\end{ganttchart}

\end{document}


An additional approach is coming directly from the package developer Wolfgang Esser-Skala as an answer to my request:

\documentclass{article}

\usepackage{pgfgantt}

\makeatletter

\newcount\@tempcntc

\def\@rawjuliantocalendarweek#1{%
\@tempcnta=#1\relax%
\pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}%
\pgfcalendardatetojulian{\@tempa-01-01+-1}{\@tempcntb}%
\advance\@tempcnta by-\@tempcntb\relax% @tempcnta = ordinal date of start date
\pgfcalendarjuliantoweekday{#1}{\@tempcntb}%
\advance\@tempcntb by1\relax% @tempcntb = week day number of start date
\pgfmathparse{int((\@tempcnta - \@tempcntb + 10) / 7)}%
}

\def\pgfcalendarjuliantocalendarweek#1#2{%
\begingroup%
\@rawjuliantocalendarweek{#1}%
\@tempcnta=\pgfmathresult\relax%
\ifnum\@tempcnta=0\relax%
\pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}%
\pgfcalendardatetojulian{\@tempa-01-01+-1}{\@tempcntc}%
\@rawjuliantocalendarweek{\@tempcntc}%
\else\ifnum\@tempcnta=53\relax%
\pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}%
\pgfcalendarifdate{\@tempa-12-31}{Thursday,Friday,Saturday,Sunday}{%
\relax%
}{%
\def\pgfmathresult{1}%
}%
\fi\fi%
\global#2=\pgfmathresult\relax%
\endgroup%
}

\ganttset{
calendar/calendarweek/.code={%
\ifgtt@calendar@eol\ganttnewline\fi%
\begingroup%
\gtt@calendar@slots=1\relax%
\pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{%
\ifdate{Sunday}{%
\gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax%
\pgfcalendarjuliantodate{\gtt@calendar@startofweek}%
{\startyear}{\startmonth}{\startday}%
\pgfcalendarjuliantocalendarweek{\gtt@calendar@startofweek}{\@tempcnta}%
\def\currentweek{\the\@tempcnta}%
\gantttitle{%
\ganttvalueof{calendar week text}%
}{%
\the\gtt@calendar@slots%
}%
\gtt@calendar@slots=1\relax%
}{%
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifnum\gtt@calendar@slots=1\relax\else%
\gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax%
\pgfcalendarjuliantodate{\gtt@calendar@startofweek}%
{\startyear}{\startmonth}{\startday}%
\pgfcalendarjuliantocalendarweek{\gtt@calendar@startofweek}{\@tempcnta}%
\def\currentweek{\the\@tempcnta}%
\gantttitle{%
\ganttvalueof{calendar week text}%
}{%
\the\gtt@calendar@slots%
}%
\fi%
}{}%
}%
\endgroup%
\gtt@calendar@eoltrue%
}%
}

\makeatother

\begin{document}

\newcount\mycount

\begin{ganttchart}[
hgrid,
vgrid,
x unit=4mm,
time slot format=isodate
]{2019-12-20}
{2020-01-20}
\gantttitlecalendar{year, calendarweek, day}
\end{ganttchart}

\noindent
\pgfcalendar{cal}
{2012-12-24}
{2013-01-07}{%
\pgfcalendarcurrentyear-\pgfcalendarcurrentmonth-\pgfcalendarcurrentday~%
\pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday}~%
\pgfcalendarjuliantocalendarweek{\pgfcalendarcurrentjulian}{\mycount}\the\mycount%
\ifdate{Sunday}{\\[\baselineskip]}{\\}%
}

%\pgfcalendarjuliantocalendarweek{}

\end{document}