在 tikz 中制作带有自动“学校周编号”的假期日历

在 tikz 中制作带有自动“学校周编号”的假期日历

我正在尝试制作双面假期日历(DIN A4,一个学年两页)。为此,我以罗伯特·克劳斯并尝试对其进行修改。目前看起来是这样的:

% DIN-A4 doublesided year calendar
% Author: Robert Krause
% License : Creative Commons attribution license
% Submitted to TeXample.net on 13 July 2018

% Modified by julia 2018

\documentclass[a4paper, ngerman, 10pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz,xparse}            % Use the calendar.sty style

\usepackage{translator} % German Month and Day names
\usepackage{fancyhdr}       % header and footer
\usepackage{fix-cm}     % Large year in header

\usepackage[ headheight = 0.8cm, hmargin=.5cm,
  top = 1.7cm, nofoot,bottom=0cm]{geometry}
\usetikzlibrary{calc}
\usetikzlibrary{calendar}
\renewcommand*\familydefault{\sfdefault}


\makeatletter
\long\def\ifnodedefined#1#2#3{%
    \@ifundefined{pgf@sh@ns@#1}{#3}{#2}%
}
\makeatother

% Names of Holidays are inserted by employing this macro
\def\termin#1#2{
  \ifnodedefined{cal-#1}{
  \node [anchor=north west, text width= 3.4cm] at
  ($(cal-#1.north west)+(3em, 0em)$) {\tiny{#2}};
  }{}
}


\newcounter{week}
\setcounter{week}{1}
\newcommand\woche[2]{
  \node [anchor=north east, align=right] at
    ($(#1.north east)+(0em, 0em)$) {\tiny{SW #2}.};}


\newcommand{\holidays}{
between=2018-10-29 and 2018-11-04,
between=2019-02-28 and 2019-02-28,
between=2019-03-01 and 2019-03-08,
between=2019-04-15 and 2019-04-26,
between=2019-06-10 and 2019-06-02,
between=2019-07-29 and 2019-09-01,
}

%Header
\renewcommand{\headrulewidth}{0.0pt}
\setlength{\headheight}{0.8cm}
\chead{
 \Huge 2018/2019
 \Large\textbf{Termine}\hfill
}
\cfoot{}

\newcommand{\kheight}{0.82}
\newcommand{\kwidth}{3.0}
\newcommand{\kshift}{3.4}
\newcommand{\calstartdate}{2018-09-10}

\newcommand{\kal}[2]{
\vspace*{-1cm}
\begin{tikzpicture}[every day/.style={anchor = north}]
\calendar[
  dates=#1,
  name=cal,
  day yshift = 3em,
  day code=
  {
    \node[name=\pgfcalendarsuggestedname,every day,shape=rectangle,
    minimum height= \kheight cm, text width = \kwidth cm, draw =
    gray]{\tikzdaytext \enskip
      \pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday}};
    \ifdate{Monday}{          
    }{}
  },
  execute before day scope=
  {
    \ifdate{day of month=1}
    {
      % Shift right
      \pgftransformxshift{\kshift cm}
      % Print month name 
      \draw (0,0)node [shape=rectangle, minimum height= \kheight cm,
      text width = \kwidth cm, fill = red, text= white, draw = red, text centered]
      {\textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth}}};
    }{}
    \ifdate{workday}
    {
      % normal days are white
      \tikzset{every day/.style={fill=white}}
      % Vacation (Germany, Baden-Wuerrtemberg) gray background
      \ifdate{#2}{%
        \tikzset{every day/.style={fill=gray!30}}
      }{}
    }{}
    % Saturdays and half holidays (Christma's and New year's eve)
    \ifdate{Saturday}{\tikzset{every day/.style={fill=red!10}}}{}
    % % Sundays and full holidays
    \ifdate{Sunday}{\tikzset{every day/.style={fill=red!20}}}{}
    %Tag der Arbeit
    \ifdate{equals=2018-10-03}{\tikzset{every
        day/.style={fill=red!20}}}{}
    % Christi Himmelfahrt
    \ifdate{equals=2019-05-30}{\tikzset{every
        day/.style={fill=red!20}}}{}
  },
 execute at begin day scope=
  {
    % each day is shifted down according to the day of month
    \pgftransformyshift{-\kheight*\pgfcalendarcurrentday cm}
  }
  ];
  % % Some Dates
  \termin{2018-10-03}{Tag der dt. Einheit}
  \termin{2019-01-01}{Neujahr}
  \termin{2019-01-06}{Heilige Drei Könige}
  \termin{2019-04-19}{Karfreitag}
  \termin{2019-04-21}{Ostersonntag}
  \termin{2019-04-22}{Ostermontag}
  \termin{2019-05-01}{Tag der Arbeit}
  \termin{2019-05-30}{Christi Himmelfahrt}
  \termin{2019-06-09}{Pfingstsonntag}
  \termin{2019-06-20}{Pfingstmontag}

\end{tikzpicture}
}

\begin{document}
\pagestyle{fancy}
\begin{center}
\kal{2018-09-10 to 2019-02-28}{
  between=2018-10-03 and 2018-10-05,
  between=2018-10-29 and 2018-11-04,
  between=2019-02-28 and 2019-02-28,
  between=2019-03-01 and 2019-03-08,
  between=2019-04-15 and 2019-04-26,
  between=2019-06-10 and 2019-06-02,
  between=2019-07-29 and 2019-09-01,
}
\kal{2019-03-01 to 2019-08-30}{
  between=2018-10-03 and 2018-10-05,
  between=2018-10-29 and 2018-11-04,
  between=2019-02-28 and 2019-02-28,
  between=2019-03-01 and 2019-03-08,
  between=2019-04-15 and 2019-04-26,
  between=2019-06-10 and 2019-06-02,
  between=2019-07-29 and 2019-09-01,
}
\pagebreak
%\kal{2019-03-01 to 2019-08-30}{\holidays}
\end{center}

\end{document}

有几点我需要帮助:

  1. 学校周数应自动编号,因此在我的示例中,2018 年 9 月 10 日星期一,星期节点的右上角应有一个小的“SW 1”。2018 年 9 月 17 日星期一应为“SW 2”等,2018 年 10 月 1 日星期一应为“SW 4”,2018 年 10 月 29 日星期一不应有标记,因为那是假期,因此“SW 8”应在 2018 年 11 月 5 日星期一(而不是“SW 9”,因为 SW 计数器不应在假期增加)。

如果一周中至少有一天不是假期,那么就应该算作一个“上学周”,并且应该在该周中第一天的右上角放置一个特定的“SW x”,该天不是假期(在我的例子中,这始终是星期一,但是对于一般解决方案,可能的情况是,例如星期一和星期二是假期,而星期三、星期四和星期五不是,在这种情况下应该在星期三打印“SW x”)。

我在当天的代码中尝试了下面的代码,但是它似乎是胡说八道。

\ifdate{Monday}{
       \tikzset{
    loop over item/.code args={####1/####2/####3}{%
      \ifdate{between=####1 and ####2}{%
      }{
        \woche{\pgfcalendarsuggestedname}{\theweek}
        \stepcounter{week}    
      }},
    loop over item/.list/.expanded=\ferien
  }          
}{}

其中 week 命令定义为:

\newcounter{week}
\setcounter{week}{1}
\newcommand\woche[2]{
  \node [anchor=north east, align=right] at
    ($(#1.north east)+(0em, 0em)$) {\tiny{SW #2}.};}
  1. 日历周数应在每个星期一的右下角。

  2. 应减少代码冗余,并尽可能简化给出日期和假日的语法,特别是我想在一个地方给出全球假日列表,在另一个全球位置给出特殊日期列表(而不是\termin每次都写)。但是应该可以定义几个日期类别(使用不同的列表和样式)。

您可能已经注意到,例如,日期“Heilige Drei Könige”打印在 2019-01-06 和 2019-06-06(这是错误的),因为我为两个日历都指定了一次日期。这尤其应该修复(我知道我可以通过复制日历代码并仅在日历的第一部分设置日期来修复它,但如上所述,我想减少代码冗余而不是增加它)。

答案1

我认为这解决了所有问题...

  1. 对于学校周的事情,我使用了两个条件:\ifWeekStarted\ifPrintSW。第一个条件每周一触发,表示一周已经开始。稍后,如果我们不在假期,并且\ifWeekStarted\ifPrintSW开关就会打开。如果最后一个开关打开,当 PGF 绘制节点时,它将步进计数器schoolweek并写入SW X。现在它将标记每周最早的一天。现在我们只需要排除可能的假期,所以如果假期是在星期一,它将保持\ifWeekStarted开关并等待星期二看它是否可以启用\ifPrintSW。我们稍后会讨论假期。

  2. 与 1 类似,但更简单,我们每周只写一个数字。但是,在这里,我们(可能)遇到了一个问题。如果您希望学校周和日历周都从 1 开始,那么代码就很简单了。但是,如果您希望日历周从 1 月 1 日开始,那么我不知道在没有 LuaTeX 的情况下是否可行(经过合理的努力)...我实施了一个解决方案,使用 pdfTeX 和 XeTeX 从 1 开始日历周编号,使用学校周,并使用 LuaTeX 调用os.date()以获取周数。既然您说可以,那就可以了 :)

  3. 我定义了一个命令\addholiday,它有三个参数:假日标识符、以逗号分隔的假日条目列表和样式设置(将由 执行\tikzset)。每个假日条目的形式为<date conditional>/<holiday name>。例如,“Heilige Drei Könige”日的形式为equals = 2019-01-06 / Heilige Drei Könige。所有其他有效的 PGF 日历日期选择键均有效,例如:between = 2018-10-08 and 2018-10-09 / Seven-day weekend!!!。然后,代码将循环遍历给定的假日并在适当的时候打印它们。此外,可以使用带星号的变体\addholiday*来定义不是假日的“特殊”日子本身,因此它仍然算作一个上学周,但是在这样的特殊日子上可以印上标题并采用特殊的格式。

这是使用 LuaTeX 编译后的第一个页面:

在此处输入图片描述

请注意,周数从 37 开始,因为date -d 2018-09-10 +%V(在 Linux 机器上)的输出显示这是一年中的第 37 周。使用 pdfTeX 或 XeTeX 编译时,它将从 1 开始。

请注意,由于Seven-day weekend!!!标签SW 5.仅出现在星期三。还请注意,由于42我使用的周数\addholiday*,因此该周仍算作学校周(SW 6.),但它会获得“假日标签”并进行相应的格式化。


我创建的第一个版本(如果有人感兴趣,你可以在编辑历史中找到它——发布两个代码太长了)使用低级定义和参数处理来定义宏\addholiday,所以它很快就变成了远的维护或修改任何东西都太麻烦了(主要是因为我嵌入功能就像我写命令时那样。不建议这样做 :)。

当前版本使用expl3的属性列表来存储假期。这使我可以轻松地向假期添加属性,查询现有属性,并在绘图代码中使用它们。

如果你调用这个命令:

\addholiday*{HDAY}{%
 , between = 2018-10-15 and 2018-10-19 / Special week!
 , equals = 2019-01-06 / Heilige Drei Könige
}
{every day/.style={fill=green!30}}

那么创建的属性树将会像这样:

在此处输入图片描述

(我对我尝试使用深感抱歉forest。代码改编自这个答案)。

执行此操作时,\addholiday命令会创建一个\l__julia_HDAY_holiday属性列表,其中包含三个属性:specialstyledates。如果使用了带星号的变体,则special属性将包含一个布尔值,否则。属性将保存最后一个参数,该参数将对这组日期进行格式化。最后一个属性将包含对另一个属性列表的引用。此属性列表将包含与您传递给的条目数一样多的属性。每个属性将是假日的名称,相应的值将是用于查找日期的 PGF 日历测试。truefalsestyle\addholidaydates\l__julia_HDAY_holiday_dates\addholiday

现在,命令\holidaycheck遍历已定义的假日列表并调用\__julia_holiday_check:nnn。最后一个宏负责检查当前日期是否为假日(带有\ifdate),如果是,则执行提供的代码。设置好所有这些结构后,实现验证以仅打印假日名称的第一个实例几乎是微不足道的 :)

对于每个节日(例如Heilige Drei Könige),我们检查是否\is_Heilige Drei Könige_printed定义了一个命令。如果没有,则将布尔值设置\WriteName为 true,写入节日的名称,并定义命令\is_Heilige Drei Könige_printed(定义为空)。如果该命令已定义(通过上一步),则将其设置\WriteName为 false 并且不写入名称。

代码:

% DIN-A4 doublesided year calendar
% Author: Robert Krause
% License : Creative Commons attribution license
% Submitted to TeXample.net on 13 July 2018

% Modified by julia 2018

\documentclass[a4paper, ngerman, 10pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz,xparse}            % Use the calendar.sty style
\usepackage{iftex}
\makeatletter
\ifLuaTeX
  \expandafter\@firstofone
\else
  \expandafter\@gobble
\fi
  {\usepackage{luacode}}

\usepackage{translator} % German Month and Day names
\usepackage{fancyhdr}       % header and footer
\usepackage{fix-cm}     % Large year in header
\usepackage{xparse}

\usepackage[ headheight = 0.8cm, hmargin=.5cm,
  top = 1.7cm, nofoot,bottom=0cm]{geometry}

\usetikzlibrary{calc}
\usetikzlibrary{calendar}
\renewcommand*\familydefault{\sfdefault}

% Names of Holidays are inserted by employing this macro
\def\termin#1#2{%
  \node [anchor=north west, text width= 3.4cm] at
    ($(#1.north west)+(3em, 0em)$) {\tiny{#2}};
}

\ifLuaTeX
\begin{luacode*}
function get_week_number(y,m,d)
  return os.date("%V",os.time{year=y,month=m,day=d})
end
\end{luacode*}
\fi

\newcounter{calweek}
\newcounter{schoolweek}

\newcommand\woche[2]{%
  \node [anchor=south east, align=right] at
    ($(#1.south east)+(0em, 0em)$) {\tiny{#2}};}

\newcommand\schulwoche[2]{%
  \node [anchor=north east, align=right] at
    ($(#1.north east)+(0em, 0em)$) {\tiny{SW #2}.};}

\ExplSyntaxOn
\bool_new:N \WriteName
\prop_new:N \l__julia_holiday_list_prop
\bool_new:N \l__julia_special_bool
\cs_new:Npn \exp_args:NNnc { \::N \::n \::c \::: }
\NewDocumentCommand\addholiday
  { s m m m }
  {
    \IfBooleanTF { #1 }
      { \bool_set_true:N \l__julia_special_bool }
      { \bool_set_false:N \l__julia_special_bool }
    \__julia_add_holiday:nnn { #2 } { #3 } { #4 }
  }
\cs_new:Npn \__julia_add_holiday:nnn #1 #2 #3
  {
    \prop_clear_new:c { l__julia_#1_holiday }
    \prop_clear_new:c { l__julia_#1_holiday_dates }
    \__julia_add_holiday_aux:ccnnn
      { l__julia_#1_holiday } { l__julia_#1_holiday_dates }
      { #1 } { #2 } { #3 }
  }
\cs_new:Npn \__julia_add_holiday_aux:NNnnn #1 #2 #3 #4 #5
  {
    \prop_put:Nnn \l__julia_holiday_list_prop { #3 } { #1 }
    \exp_args:NNnV
    \prop_put:Nnn #1 { special } \l__julia_special_bool
    \prop_put:Nnn #1 { dates } { #2 }
    \prop_put:Nnn #1 { style } { #5 }
    \clist_map_inline:nn { #4 }
      { \__julia_prop_split_add:Nn #2 { ##1 } }
    % \prop_show:N #1
  }
\cs_generate_variant:Nn \__julia_add_holiday_aux:NNnnn { ccnnn }
\cs_new:Npn \__julia_prop_split_add:Nn #1 #2
  { \__julia_prop_split_add:Nw #1 #2 \q_stop }
\cs_new:Npn \__julia_prop_split_add:Nw #1 #2 / #3 \q_stop
  {
    \exp_args:NNff
    \prop_put:Nnn #1
      { \tl_trim_spaces:n { #3 } }
      { \tl_trim_spaces:n { #2 } }
  }
\cs_new:Npn \holidaycheck #1
  {
    \cs_gset_eq:NN \HolidayStyle \c_empty_tl
    \prop_map_inline:Nn \l__julia_holiday_list_prop
      {
        \prop_get:NnN ##2 { dates   } \HLprop
        \prop_get:NnN ##2 { style   } \HLstyle
        \prop_get:NnN ##2 { special } \HLtype
        \prop_map_inline:Nn \HLprop
          {
            \__julia_holiday_check:nnn
              { #1 } { ####1 } { ####2 }
          }
      }
  }
\cs_new:Npn \__julia_holiday_check:nnn #1 #2 #3
  {
    % #1 is the code passed to \holidaycheck
    % #2 is the holiday name
    % #3 is the holiday date
    \ifdate { #3 }
      {
        \cs_set:Npn \name { #2 }
        \cs_if_exist:cTF { is_ #2 _printed }
          { \bool_set_false:N \WriteName }
          { \bool_set_true:N \WriteName }
        #1
      }
      { }
  }
\cs_new:Npn \HolidaySetUsed #1
  { \cs_gset_eq:cN { is_ #1 _printed } \c_empty_tl }
\ExplSyntaxOff

%Header
\renewcommand{\headrulewidth}{0.0pt}
\setlength{\headheight}{0.8cm}
\chead{%
 \Huge 2018/2019
 \Large\textbf{Termine}\hfill
}
\cfoot{}

\newcommand{\kheight}{0.82}
\newcommand{\kwidth}{3.0}
\newcommand{\kshift}{3.4}
\newcommand{\calstartdate}{2018-09-10}

\newif\ifWeekStarted
\WeekStartedfalse
\newif\ifPrintSW
\PrintSWfalse
\newif\ifHasHoliday

\newcommand{\kal}[2]{%
\vspace*{-1cm}
\begin{tikzpicture}[every day/.style={anchor = north}]
\calendar[
  dates = #1,
  name = cal,
  day yshift = 3em,
  day code = 
    {%
      \holidaycheck{%
        \global\let\HolidayStyle\HLstyle
      }%
      \expandafter\tikzset\expandafter{\HolidayStyle}%
      \node [
        name = \pgfcalendarsuggestedname,
        every day,
        shape = rectangle,
        minimum height = \kheight cm,
        text width = \kwidth cm,
        draw = gray]
        {\tikzdaytext\enskip
         \pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday}%
        };%
      \holidaycheck{%
        \IfBooleanF{\HLtype}{\global\PrintSWfalse} % A holiday
        \IfBooleanTF{\WriteName}
          {%
            \termin{\pgfcalendarsuggestedname}{\name}{}%
            \HolidaySetUsed{\name}%
          }%
          {}%
      }%
      \ifPrintSW
        \stepcounter{schoolweek}%
        \global\WeekStartedfalse
        \global\PrintSWfalse
        \schulwoche{\pgfcalendarsuggestedname}{\arabic{schoolweek}}%
      \fi
      \ifdate{Monday}{%
        \ifLuaTeX
          \setcounter{calweek}{%
            \directlua{%
              tex.print(
                get_week_number(
                  \pgfcalendarcurrentyear,
                  \pgfcalendarcurrentmonth,
                  \pgfcalendarcurrentday
                )
              )
            }%
          }%
        \else
          \stepcounter{calweek}%
        \fi
        \woche{\pgfcalendarsuggestedname}{\arabic{calweek}}%
      }{}%
    },
  execute before day scope=
    {%
      \ifdate{day of month=1}
      {%
        % Shift right
        \pgftransformxshift{\kshift cm}
        % Print month name 
        \draw (0,0) node [shape=rectangle, minimum height= \kheight cm,
          text width = \kwidth cm, fill = red, text= white, draw = red, text centered]
          {\textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth}}};
      }{}%
      \ifdate{Monday}{%
        \global\WeekStartedtrue
      }{}
      \ifdate{workday}
      {%
        % normal days are white
        \tikzset{every day/.style={fill=white}}
        % Vacation (Germany, Baden-Wuerrtemberg) gray background
        \expandafter\ifdate\expandafter{#2}{%
          \tikzset{every day/.style={fill=gray!30}}
        }{%
          \ifWeekStarted
            \global\PrintSWtrue
          \fi
        }%
      }{}%
      % Saturdays and half holidays (Christma's and New year's eve)
      \ifdate{Saturday}{%
        \tikzset{every day/.style={fill=red!10}}%
      }{}%
      % % Sundays and full holidays
      \ifdate{Sunday}{%
        \tikzset{every day/.style={fill=red!20}}%
      }{}%
    },
  execute at begin day scope=
    {%
      % each day is shifted down according to the day of month
      \pgftransformyshift{-\kheight*\pgfcalendarcurrentday cm}
    }
  ];
\end{tikzpicture}
}

\addholiday{normal holidays}{%
 , between = 2018-10-08 and 2018-10-09 / Seven-day weekend!!!
 , equals = 2018-10-03 / Tag der dt. Einheit
 , equals = 2019-01-01 / Neujahr
 , equals = 2019-01-06 / Heilige Drei Könige
 , equals = 2019-04-19 / Karfreitag
 , equals = 2019-04-21 / Ostersonntag
 , equals = 2019-04-22 / Ostermontag
 , equals = 2019-05-01 / Tag der Arbeit
 , equals = 2019-05-30 / Christi Himmelfahrt
 , equals = 2019-06-09 / Pfingstsonntag
 , equals = 2019-06-20 / Pfingstmontag
}
{every day/.style={fill=gray!30}}

\addholiday*{very special week}{%
 , between = 2018-10-15 and 2018-10-19 / Special week!
}
{every day/.style={fill=green!30}}

\newcommand{\HolidayList}{%
  between=2018-10-03 and 2018-10-05,
  between=2018-10-29 and 2018-11-04,
  between=2019-02-28 and 2019-02-28,
  between=2019-03-01 and 2019-03-08,
  between=2019-04-15 and 2019-04-26,
  between=2019-06-10 and 2019-06-02,
  between=2019-07-29 and 2019-09-01,
}

\begin{document}
\pagestyle{fancy}
\begin{center}
\kal{2018-09-10 to 2019-02-28}{\HolidayList}
\kal{2019-03-01 to 2019-08-30}{\HolidayList}
\pagebreak
% \kal{2019-03-01 to 2019-08-30}{\holidays}
\end{center}

\end{document}

答案2

我们可以使用 PGF/TikZ 和 TeX 来实现这一点。

我在用着

  • 我的qrr.calendar图书馆 [12] 为了
    • /pgf/calendar/and最先出现的钥匙在我的另一个回答中
    • 周数编号(简写:\%n-= 1\%n== ␣1\%n0= 01),
    • if可以在另一个内部使用的密钥if
  • 一个 LaTeX 计数器schoolweek,每个上学周都会增加,
  • 一个 LaTeX 计数器lastschoolweek,用于存储上次排版的学校周数。
  • /utils/if键用于检查当前周的学校周标记是否已经排版。

使用列表应用样式和标签。

处理程序/.list/.expand once仅存储日期或范围的列表宏一起使用。这样,您可以说

\newcommand*\termine{
  equals=12-25 / Christmas Day / Holiday,
  …}

通过这样的关键设置

\tikzset{termine/.style args={#1/#2/#3}{
  if={(#1) [days={label:#2,#3}]}

您可以termine/.list/.expand once=\termine这样做,PGF / TikZ 只会检查所有这些,如果为真,它会应用标签#2和样式#3

这就是钥匙的力量/tikz/if,因为这样人们可以控制条件和动作。

使用“裸”伪路径运算符无法实现这一点if (<cond>) [<true>]

给学校周数编号

这些[de]activate SW键仅用于激活(取消激活)可能的学校周标签(所有标记均以 TikZ 形式实现label):

activate SW/.style={
  mark SW/.style = {% only mark SW if we didn't already set this yearweek's SW
    /utils/if={\value{lastschoolweek}!=\the\numexpr\pgfcalendarcurrentweeknumber\relax}{
      /utils/exec=\setcounter{lastschoolweek}{\%n0},
      label = {[anchor=north east, every SW mark/.try]
        north east:SW~\stepcounter{schoolweek}\theschoolweek}}{}}},
deactivate SW/.style = {mark SW/.style=},

为此,mark SW当应用节点选项时,样式必须最后执行。因此,最后一个条件是

if = (workday) [ days = mark SW ]

必须包含假日风格 (Feiertag、Ferien 等) 才能deactivate SW禁用该mark SW风格。

以及更多

如果我们还设定

/pgf/calendar/strip first/.style args={#1/#2}{#1},
/pgf/calendar/strip first yesterday/.style args={#1/#2}{yesterday={#1}}

我们可以bereiche按如下方式扩展密钥:

bereiche/.style args={#1--#2/#3/#4}{
  if = {(between = #1 and #2) [
    if = {(workday)                    [days = {style=#4}]},
    if = {(and = {workday, equals=#1}) [days = {mark up = {#3}}]},
    if = {(and = {Monday,  between=#1+1 and #2, not = {strip first/.list/.expand once=\termine}})
      [days = {mark up = {#3 (Fs.)}} ]
    else [
      if = {(and={between=#1+2 and #2, workday, not=Monday,
             not={not={strip first yesterday/.list/.expand once=\termine}}})
        [days = {mark up = {#3 (Fs.)}}] }
    ]}
  ]}}

我们得到了这样的标记奥斯特费恩 (Fs.)但仅限于周末和节假日后的几天。

代码

\documentclass[ngerman,multi=tikzpicture,varwidth=false]{standalone}
\usepackage{translator,tikz,babel,libertine}
\usetikzlibrary{calendar,qrr.calendar}
\newcounter{schoolweek}
\newcounter{lastschoolweek}
\makeatletter
\pgfkeys{/utils/if/.code n args={3}{%
  \pgfmathparse{#1}\ifdim\pgfmathresult pt=0pt\relax
    \expandafter\pgfutil@firstoftwo\else\expandafter\pgfutil@secondoftwo\fi
    {\pgfkeysalso{#3}}{\pgfkeysalso{#2}}}}
\makeatother
\tikzset{
  %%% the actual calendar style
  month columns/.style={% Mondays get yearweek number, workdays possibly schoolweek number
    month width/.initial=47.5mm, day height/.initial=6.2mm,% (297-10)/6 and (210-10)/32.2
    day code={\node[every day]{\tikzdaytext};}, day text={\%d=~~\%w.},
    month code={\node[every month]{\tikzmonthtext};},
    textual/.style            = {
      draw=gray, font=\strut, text depth=+0pt, outer sep=+0pt, anchor=south,
      text width=\pgfkeysvalueof{/tikz/month width}-2*(\pgfkeysvalueof{/pgf/inner xsep})},
    every day/.append style   = {textual, align=left, minimum height=\pgfkeysvalueof{/tikz/day height}},
    every month/.append style = {textual, align=center, minimum height=1.2*(\pgfkeysvalueof{/tikz/day height}), font=\Large\bfseries, fill=red, text=white},
    execute before day scope  = {%
      \ifdate{day of month=1, equals=\pgfcalendarbeginiso}{\tikzmonthcode}{}%
      \ifdate{equals=\pgfcalendarbeginiso}{\pgftransformyshift{-\numexpr\pgfcalendarifdateday-1\relax*(\pgfkeysvalueof{/tikz/day height})}}{}%
      \pgftransformyshift{-(\pgfkeysvalueof{/tikz/day height})}},
    execute after day scope   = {%
      \ifdate{end of month=1}{%
        \pgftransformyshift{(\numexpr\pgfcalendarifdateday\relax)*(\pgfkeysvalueof{/tikz/day height})}%
        \pgftransformxshift{\pgfkeysvalueof{/tikz/month width}}}{}}}}
  
\newcommand*\termine{% repeating fixed day
  equals=01-01 / Neujahr             / Feiertag,
  equals=01-06 / Heilige Drei Könige / chrFeiertag,
  equals=03-08 / Int. Frauentag      / Feiertag,
  equals=05-01 / Tag der Arbeit      / Feiertag,
  equals=10-03 / Tag der dt. Einheit / Feiertag,
  equals=12-25 / 1. Weihnachtstag    / chrFeiertag,
  equals=12-26 / 2. Weihnachtstag    / chrFeiertag,
  Easter=-2    / Karfreitag          / chrFeiertag,
  Easter= 0    / Ostersonntag        / chrFeiertag,
  Easter= 1    / Ostermontag         / chrFeiertag,
  Easter=39    / Christi Himmelfahrt / chrFeiertag,
  Easter=49    / Pfingstsonntag      / chrFeiertag,
  Easter=50    / Pfingstmontag       / chrFeiertag}
\newcommand*\bereiche{% holidays
  2022-07-07--2022-08-20 / Sommerferien          / Ferien,
  2022-09-06--2022-09-08 / Extraferien           / {Ferien, fill=blue!50},
  2022-09-14--2022-09-20 / keine Ferien          / keineFerien,
  2022-10-24--2022-11-05 / Herbstferien          / Ferien,
  2022-12-22--2023-01-02 / Weihnachtsferien      / Ferien,
  2023-01-30--2023-02-04 / Winterferien          / Ferien,
  2023-04-03--2023-04-14 / Osterferien           / Ferien,
  2023-05-19--2023-05-19 / Brückentag            / Ferien,
  2023-05-30--2023-05-30 / Pfingstferien         / Ferien,
  2023-07-13--2023-08-25 / Sommerferien          / Ferien}
\tikzset{
  %%% set the first appearing week to the given number
  start SW/.code=\setcounter{schoolweek}{\numexpr#1-1\relax},
  %%% marking styles
  mark up/.style       = {label = {[anchor=north west, every mark up]   north west: #1}},
  mark down/.style     = {label = {[anchor=south west, every mark down] south west: #1}},
  mark KW/.style       = {label = {[anchor=south east, every KW mark]   south east: KW~\%n-}},
  every K- mark/.style = {font = \scriptsize, text = black, text depth = +0pt, inner ysep = .3em},
  every KW mark/.style = {every K- mark, text = gray!50!black}, every SW mark/.style = every K- mark,
  every mark/.style    = {font = \scriptsize, text = black, xshift = +3.3em, text depth = +0pt, inner ysep = .3em},
  every mark up/.style = every mark, every mark down/.style = every mark,
  %
  %%% SW marking is special, let's have keys that (de)activate this
  activate SW/.style={
    mark SW/.style = {% only mark SW if we didn't already set this yearweek's SW
      /utils/if={\value{lastschoolweek}!=\the\numexpr\pgfcalendarcurrentweek\relax}{
        /utils/exec=\setcounter{lastschoolweek}{\%n0},
        label = {[anchor=north east, every SW mark/.try]
          north east:SW~\stepcounter{schoolweek}\theschoolweek}}{}}},
  deactivate SW/.style = {mark SW/.style=},
  %
  %%% Parsing
  bereiche/.style args={#1--#2/#3/#4}{
    if = {(between = #1 and #2) [
      if = {(workday)                    [days = {style=#4}]},
      if = {(and = {workday, equals=#1}) [days = {mark up = {#3}}]}
    ]},
  },
  termine/.style args = {#1/#2/#3}{if = {(#1)    [days = {mark down = {#2},style=#3} ]}},
  %
  %%% visualization
  Feiertag/.style     = {fill = red!75,         deactivate SW},
  chrFeiertag/.style  = {fill = red!75!blue!50, deactivate SW},
  Ferien/.style       = {fill = gray!25,        deactivate SW},
  keineFerien/.style  = {fill = green!50}}
\tikzset{
  my calendar/.style = {
    month columns, if = {(Monday) [days=mark KW]}, if = (workday) [activate SW],
    bereiche/.list/.expand once=\bereiche, termine/.list/.expand once=\termine,
    if = {(Sunday)   [days={fill=red!50}]}, if = {(Saturday) [days={fill=red!25}]},
    if = {(workday)  [days={mark SW/.try}]}}}
\begin{document}\sffamily\small
\tikz\calendar[dates = 2022-08-01 to 2023-01-31, my calendar, start SW = 1];
\tikz\calendar[dates = 2023-02-01 to 2023-07-31, my calendar];
\end{document}

输出

在此处输入图片描述

相关内容