除了日历月份名称外,我还添加了日历周计数器(第 1 周至第 52 周)放入图表标题中pgfgantt
。
最小工作示例(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}
结果截图(2019 - 2020 年):
结果截图(2020 - 2021 年):
问题说明:
虽然当前的周数counter
对于 2019 年至 2020 年(计算52
2019 年的周数)来说完全正常,但从 2020 年到 2021 年却出现了一些小故障(错误地计算了52
周数而不是53
周数)。
问题:
按照国际周计算标准ISO 8601, 这第一个日历周每年的一周是包含每年第一个星期四。此后,下一个计算周从星期一开始(=作为第二个日历周)。因此:2019 年有52
几周,而 2020 年有53
几周。
从维基百科:
“ISO 8601 包括 ISO 周日期系统,即周的编号系统 - 每周从周一开始,并与包含该周星期四的年份相关联(因此,如果一年开始于周五至周日的长周末,则一年的第一周将在那之后开始)。例如,2004 年的第一周(2004W01)从 2003 年 12 月 29 日星期一到 2004 年 1 月 4 日星期日,因为星期四是 2004 年 1 月 1 日,而 2005 年的第一周(2005W01)从 2005 年 1 月 3 日星期一到 2005 年 1 月 9 日星期日,因为星期四是 2005 年 1 月 6 日,因此是 2005 年的第一个星期四。“
问题:
考虑到ISO 8601标准计数方案?
答案1
我同意 Steven 的观点,这可能有点过头了。另一方面,calendar
图书馆有很好的\pgfcalendarifdate
内置功能,所以……
\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}
答案2
由于 53 周的年份只是偶尔出现,而且绝不会连续出现,因此我认为在这种情况下,为特定情况硬编码 53 周比\ifnum\startyear=2020
开发符合 ISO 8601 的版本更容易。这是我在 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}
答案3
软件包开发人员 Wolfgang Esser-Skala 直接给出了另一种方法,以回答我的请求:
\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%
\advance\gtt@calendar@startofweek by1\relax%
\advance\gtt@calendar@startofweek by-\gtt@calendar@slots\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%
}{%
\advance\gtt@calendar@slots by1%
}%
\ifdate{equals=\pgfcalendarendiso}{%
\ifnum\gtt@calendar@slots=1\relax\else%
\advance\gtt@calendar@slots by-1\relax%
\gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax%
\advance\gtt@calendar@startofweek by1\relax%
\advance\gtt@calendar@startofweek by-\gtt@calendar@slots\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}