pgfgantt:如何根据 ISO 8601 计数方案显示周数?

pgfgantt:如何根据 ISO 8601 计数方案显示周数?

除了日历月份名称外,我还添加了日历周计数器(第 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 年):

结果截图1

结果截图(2020 - 2021 年):

在此处输入图片描述


问题说明:

虽然当前的周数counter对于 2019 年至 2020 年(计算522019 年的周数)来说完全正常,但从 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}

相关内容