在 pgfcalendar 中匹配重复日期

在 pgfcalendar 中匹配重复日期

我使用的日历深受现有日历的启发这里。我对我所拥有的非常满意,但是今天,我决定我需要一种方法来匹配重复日期。

我尝试了以下方法:

% Definition
\pgfkeys{/pgf/calendar/recurring/.default = 0}
\pgfkeys{/pgf/calendar/recurring/.code =
  {
    \foreach \m / \d in {1/4,1/8,2/1}
      {
        \ifnum\pgfcalendarifdatemonth=\m\relax
          \ifnum\pgfcalendarifdateday=\d\relax
            \global\pgfcalendarmatchestrue
          \fi
        \fi
       }
  }
}

% Usage
if (recurring) [event]

这可以正常工作,但并不实用,因为我需要知道所有日期并将它们包含在循环中。最重要的是,如果我想添加多个重复事件,它就无法重复使用。

我的想法是改变我的重复方法如下:

  • 添加一年中的某一天的起点(例如:01-04为了1 月 4 日)。
  • 添加以天为单位的时间段(例如:10)。
  • 添加一些事件。

第一步

我的第一步是使用参数来处理日期,而不是将它们放在我的定义中。这样我就可以在不同的日期集合中重​​复使用我的定义。这仍然需要大量配置,但至少我可以为多个重复事件创建一个定义。

这就是我得到的:

% Definition

\pgfkeys{/pgf/calendar/recurring/.default = 0}
\pgfkeys{/pgf/calendar/recurring/.code = 
  {
    \foreach \m/\d in {#1}
      {
        \ifnum\pgfcalendarifdatemonth=\m\relax
          \ifnum\pgfcalendarifdateday=\d\relax
            \global\pgfcalendarmatchestrue
          \fi
        \fi
      }
  }
}

% Usage
if (recurring={01/04,01/14,01,24}) [event]

第二步

我的第二步是计算日期,包括起始点、周期和事件数量。由于我不知道事件发生的月份和日期,我决定使用儒略日期来计算所有内容。这是我得到的:

% Definition
\pgfkeys{/pgf/calendar/recurring/.default = 0}
\pgfkeys{/pgf/calendar/recurring/.code 3 args={3} 
  {
    \foreach \events in {0,..,#3}
      {
        \pgfcalendardatetojulian{\year-#1+#2*\events}{\jul}
        \ifnum\pgfcalendarifdatejulian=\jul\relax
          \global\pgfcalendarmatchestrue
        \fi
      }
  }
}

% Usage
if (recurring={01-04}{14}{3}) [event]

第一个参数是开始日期,第二个参数是时间段,第三个参数是事件数量。

这就是我被困住的地方。什么都不起作用。在 texmaker 中,我遇到以下错误:

! Illegal parameter number in definition of \pgf@temp.
<to be read again>
3
l.310 }
You meant to type ## instead of #, right?
Or maybe a } was forgotten somewhere earlier, and things
are all screwed up? I'm going to assume that you meant ##.

我能做些什么来解决这个问题?我是否使用了完全错误的路径来实现我想要的目标?

编辑#1

以下是最后一个可行解决方案的一个工作示例:

% Birthday calendar
% Author: Hakon Malmedal
\documentclass[fontsize=20pt]{scrartcl}
\usepackage[french]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[margin=1cm,a4paper,landscape]{geometry}
\pagestyle{empty}
\usepackage{graphicx}
\usepackage{tikz}
%%%<
\usepackage{verbatim}
%%%>
\begin{comment}
:Title: Birthday calendar
:Tags: Calendar library;Calendars
:Author: Hakon Malmedal
:Slug: birthday-calendar
\end{comment}
\usetikzlibrary{calendar,fit}
\usepackage{expl3,xparse}

%% Adapted from http://tex.stackexchange.com/a/10199/4771
\makeatletter%
\tikzoption{day headings}{\tikzstyle{day heading}=[#1]}
\tikzstyle{day heading}=[]
\tikzstyle{day letter headings}=[
    execute before day scope={ \ifdate{day of month=1}{%
      \pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}%
      \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}%
      \pgftransformyshift{-\pgf@ya}
      \foreach \d/\l in {0/Lundi,1/Mardi,2/Mercredi,3/Jeudi,%
                         4/Vendredi,5/Samedi,6/Dimanche} {
        \pgf@xa=\d\pgf@xa%
        \pgftransformxshift{\pgf@xa-\cellwidth/2}%
        \pgftransformyshift{\pgf@ya}%
        \node[above=-0.5ex,day heading]{\l};%
      }
    }{}%
  }%
]
\makeatother%
%% End

%% Adapted from pgf source
\def\pgfcalendarmonthname#1{%
  \translate{\ifcase#1\or Janvier\or Février\or Mars\or Avril\or
    Mai\or Juin\or Juillet\or Août\or Septembre\or Octobre\or
    Novembre\or Decembre\fi}%
}

\makeatletter
\tikzstyle{month label above centered}=[%
  execute before day scope={%
    \ifdate{day of month=1}{%
      {
        \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}%
        \pgf@xb=\tikz@lib@cal@width\pgf@xa%
        \advance\pgf@xb by-\pgf@xa%
        \pgf@xb=.5\pgf@xb%
        \pgftransformxshift{\pgf@xb}%
        \pgftransformxshift{-\cellwidth/2}%
        \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}%
        \pgftransformyshift{0.333\pgf@y}
        \tikzmonthcode%
      }
    }{}},
  every month/.append style={anchor=base}
]
\makeatother
%% End

\ExplSyntaxOn

%% Adapted from http://tex.stackexchange.com/a/56214/4771
%%
% first of all we define the user level commands
\NewDocumentCommand{\addtext}{ m }{ \bdaycal_input_add:n { #1 } }
\NewDocumentCommand{\addtextyear}{ mm }{ \bdaycal_input_add_y:nn { #1 } { #2 } }
\NewDocumentCommand{\showtext}{ }{ \bdaycal_output_direct: }

% allocate variable:
% a sequence for global storage of the inputs;
\seq_new:N \g_bdaycal_input_seq

% store globally an input in the sequence
\cs_new:Npn \bdaycal_input_add:n #1
 {
  \seq_gput_right:Nn \g_bdaycal_input_seq { #1 }
 }

\cs_new:Npn \bdaycal_input_add_y:nn #1 #2
 {
  \seq_gput_right:Nn \g_bdaycal_input_seq { #1 ~ ( \int_to_arabic:n
    { \pgfcalendarifdateyear - #2 } ) }
 }

% how to output in direct order; we simply do a mapping function calling
% \bdaycal_print:n after incrementing the counter
\cs_new_protected:Npn \bdaycal_output_direct:
 {
  \seq_map_inline:Nn \g_bdaycal_input_seq
   {
    \bdaycal_print:n { ##1 }
   }
  \seq_gclear:N \g_bdaycal_input_seq
 }

% the printing macro; change here for adapting to your wishes
\cs_new:Npn \bdaycal_print:n #1
 {
  #1 \par
 }
%% End

%% Knuth's AoCP, vol 1, 2nd ed, pp 155--156
\int_new:N \l_easter_Y_int
\int_new:N \l_easter_G_int
\int_new:N \l_easter_C_int
\int_new:N \l_easter_X_int
\int_new:N \l_easter_Z_int
\int_new:N \l_easter_D_int
\int_new:N \l_easter_E_int
\int_new:N \l_easter_N_int
\int_new:N \l_easter_M_int
\int_new:N \l_easter_julian_day_int

\cs_new:Nn \easter_sunday:n {

  \int_set:Nn \l_easter_Y_int { #1 }

  \int_set:Nn \l_easter_G_int {
    \int_mod:nn { \l_easter_Y_int } { 19 } + 1
  }

  \int_set:Nn \l_easter_C_int {
    \int_div_truncate:nn { \l_easter_Y_int } { 100 } + 1
  }

  \int_set:Nn \l_easter_X_int {
    \int_div_truncate:nn { 3 * \l_easter_C_int } { 4 } - 12
  }

  \int_set:Nn \l_easter_Z_int {
    \int_div_truncate:nn { 8 * \l_easter_C_int + 5 } { 25 } - 5
  }

  \int_set:Nn \l_easter_D_int {
    \int_div_truncate:nn { 5 * \l_easter_Y_int } { 4 } - \l_easter_X_int - 10
  }

  \int_set:Nn \l_easter_E_int {
    \int_mod:nn { 11 * \l_easter_G_int + 20 + \l_easter_Z_int
      - \l_easter_X_int } { 30 }
  }

  % \int_mod:nn behaves strangely.
  \int_compare:nNnT { \l_easter_E_int } < { 0 }
  {
    \int_add:Nn \l_easter_E_int { 30 }
  }

  \int_compare:nNnTF { \l_easter_E_int } = { 25 }
  { % true
    \int_compare:nNnT { \l_easter_G_int } > { 11 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }
  { % false
    \int_compare:nNnT { \l_easter_E_int } = { 24 }
    { % true
      \int_incr:N \l_easter_E_int
    }
  }

  \int_set:Nn \l_easter_N_int { 44 - \l_easter_E_int }

  \int_compare:nNnT { \l_easter_N_int } < { 21 }
  { % true
    \int_add:Nn \l_easter_N_int { 30 }
  }

  \int_add:Nn \l_easter_N_int {
    7 - \int_mod:nn { \l_easter_D_int + \l_easter_N_int } { 7 }
  }

  \int_compare:nNnTF { \l_easter_N_int } > { 31 }
  { % true
    \int_sub:Nn \l_easter_N_int { 31 }
    \int_set:Nn \l_easter_M_int { 4 } % April
  }
  { % false
    \int_set:Nn \l_easter_M_int { 3 } % March
  }

  \pgfcalendardatetojulian { \l_easter_Y_int -
     \l_easter_M_int - \l_easter_N_int
  } { \l_easter_julian_day_int }

}


\ExplSyntaxOff

\pgfkeys{/tikz/event/.code = \addtext{#1}}

\pgfkeys{/pgf/calendar/recurring/.default = 0}
\pgfkeys{/pgf/calendar/recurring/.code = 
  {
    \foreach \m/\d in {#1}
      {
        \ifnum\pgfcalendarifdatemonth=\m\relax
          \ifnum\pgfcalendarifdateday=\d\relax
            \global\pgfcalendarmatchestrue
          \fi
        \fi
      }
   }
}

\pgfkeys{/tikz/day code =
  {
    \node (lower right) at (0,0) [above left,font=\Large] {\tikzdaytext};
    \node (upper left) at (-\cellwidth,\cellheight)
    [below right,align=left,text width=\cellwidth-\pgflinewidth,
    font=\tiny,black] {\showtext};
    \node (lower left) at (-\cellwidth,0) {};
    \node[rounded corners, draw,
          fit=(lower right) (upper left) (lower left),
          inner sep=1mm] {};
  }
}

\pgfkeys{/tikz/inner sep = 0pt}

\pgfkeys{/tikz/day xshift=\cellwidth+2mm+2mm}

\pgfkeys{/tikz/day yshift=\cellheight+2mm+2mm}

\newlength{\cellheight}
\setlength{\cellheight}{25mm}
\newlength{\cellwidth}
\setlength{\cellwidth}{35mm}

\begin{document}

\centering

\begin{tikzpicture}[thick]
  \calendar[dates=2024-01-01 to 2024-01-last,
            week list,
            month label above centered,
            month text=\textsc{\%mt \%y0},
            day headings={font=\footnotesize},
            day letter headings]
    if (recurring={01/04,01/14,01/24}) [event={Something}]
;
\end{tikzpicture}

\end{document}

答案1

以下是recurring语法测试

重复 =事件次从日期每一个重复[|]

在哪里

  • date是通常日历语法中的日期,YYYY-MM-DD其中YYYY-是可选的,
  • occurrences是事件应重复的次数(除了第一次重复的次数date),
  • repeat是重复事件与
  • [|] 要么 ,days要么weeks

关键词timesdaysweeks可以是单数timedayweek

的值repeat将由 PGFMath 进行评估(因此可以是8-2^2),而occurrences只能由 eTeX 进行评估(8-2*2可以工作)。

您的 1 月 4 日、14 日和 20 日活动将是

recurring = 2 times from 01-04 every 10 days

代码

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calendar}
\makeatletter
\pgfqkeys{/pgf/calendar}{
  recurring/.code args={#1 time#2 from #3 every #4 #5}{%
    % This macro converts yyyy-mm-dd to julian date (in \pgfutil@tempctna)
    % as well as mm-dd with the current year
    \pgfcalendar@special@datetojulian{#3}%
    \pgfqkeys{/pgf/calendar/@recurring}{#5={#4}{#1}}},
  @recurring/days/.code 2 args={% #1 is the every, #2 is the times
    \ifnum\pgfintmod{\pgfcalendarifdatejulian-\pgfutil@tempcnta}{#1}=0
      \pgfmathsetcount\c@pgf@counta{#2}%
      \unless\ifnum\pgfintdivtruncate
        {\pgfcalendarifdatejulian-\pgfutil@tempcnta}{#1}>\c@pgf@counta
        \pgfcalendarmatchestrue
      \fi
    \fi},
  @recurring/weeks/.style 2 args={/pgf/calendar/@recurring/days={7*(#1)}{#2}},
  @recurring/day/.style={/pgf/calendar/@recurring/days={#1}},
  @recurring/week/.style={/pgf/calendar/@recurring/weeks={#1}}}
\makeatother
\begin{document}
\tikz
  \calendar[
    dates=2023-01-01 to 2023-03-31,
    month list, month label left, month yshift=1.25em]
  if (Sunday) [days={fill=red!50}]
  if (recurring = 17 times from 2023-01-01 every  2 days)  [green!50!black]
  if (recurring =  4 times from 2023-02-06 every  2 weeks) [blue!50]
  if (recurring =  2 times from      01-04 every 10 days)  [days={fill=green!50}];
\end{document}

输出

在此处输入图片描述

相关内容