任务报告的时间计算

任务报告的时间计算

考虑一下这个MWE:

\documentclass{article}

\newenvironment{dayreport}{\begin{tabular}{ll}\hline Task & Time\\\hline}{\hline\end{tabular}}
\newcommand{\task}[2]{#1 & #2\\}

\begin{document}
\begin{dayreport}
\task{a}{1 hr\hphantom{s}}
\task{b}{2 hrs}
\task{c}{1 hr 30 mins}
\end{dayreport}
\end{document}

输出如下所示:

任务

我想自动执行一些任务,例如输入时间和计算总时间。时间输入示例:

  • \task{a}{1}会产生a & 1 hr\hphantom{s}
  • \task{a}{1:30}会产生a & 1 hr 30 mins
  • \task{a}{2}会产生a & 2 hrs

总时间计算:

\begin{dayreport}
\task{a}{1}
\task{a}{1:30}
\task{a}{2}
\begin{endreport}

Total time: & 4 hrs 30 mins \\结束时会产生dayreport

在 LaTeX 中可以实现类似的功能吗(我可能需要字符串拆分、简单算术和 if-then-else 结构)?我是否应该编写一个简短的程序来解析输入并输出适当的 LaTeX 代码?

答案1

\makeatletter
\def\task#1{\@task#1::\@nil}
\def\@task#1:#2:#3\@nil{%
  \if\relax\detokenize{#2}\relax
    % no minutes
    #1 hr\ifnum#1=\@ne\hphantom{s}\else s\fi
  \else
    #1 hr\ifnum#1=\@ne\else s\fi
    \ #2 mins
  \fi}
\makeatother
...
\task{1}

\task{1:30}

\task{2:54}

结果

问题在于解析结果。在\task{1}标记列表之后

\@task 1::\@nil

因此,#11,而#2#3为空(的参数\@task由分号和分隔\@nil)。\task{1:30}得到之后

\@task 1:30::\@nil

所以#11#230#3:。其余的只是遵循条件:当是空\if\relax\detokenize{#2}\relax时为真。如果要存储计算时间,只需在条件的分支中#2添加一些即可。\def

答案2

整理 egreg 针对问题给出的建议将命令转换为结果存储环境参数\detokenize 的确切语义是什么?以及这个,我设法创造了我想要的东西。

为了完整性,我提供了代码。但仍有一些不完善的地方:task{0:15}将打印0 hrs 15 mins,表格不占满整个空间\textwidth等等。作为概念证明,我很满意。

报告.tex

\documentclass{workreport}

\begin{document}
\begin{dayreport}{June 13, 2011}
\task{First task}{3}
\task{Second task}{1:12}
\task{Third task}{3:15}
\end{dayreport}

\begin{dayreport}{June 14, 2011}
\task{Fourth task}{1:15}
\task{Fifth task}{2}
\task{Sixth task}{1}
\end{dayreport}

\totaltime

\end{document}

输出

任务报告

工作报告.cls

% workreport.cls
\ProvidesClass{workreport}
\LoadClass[a4paper,12pt]{article}

% infix arithmetic
\usepackage{calc}

% setting section titles
\usepackage{titlesec}
\titleformat{\section}{\Large\scshape\raggedright}{}{0em}{}[]

% nicer looking table rules
\usepackage{booktabs}

% counters for time calculation
\newcounter{totaltime}
\setcounter{totaltime}{0}
\newcounter{dailytime}
\setcounter{dailytime}{0}
\newcounter{hours}
\setcounter{hours}{0}
\newcounter{minutes}
\setcounter{minutes}{0}

% required for xappto command
\usepackage{etoolbox}

\newcommand{\totaltimerows}{}
\newcommand{\totaltime}{
\section*{Total Work Hours}
\begin{tabular}{p{0.75\textwidth}r}
\toprule
Day     &   Work hours \\
\midrule
\totaltimerows
\bottomrule
\setcounter{minutes}{\thetotaltime-((\thetotaltime/60)*60)}
\setcounter{hours}{\thetotaltime/60}
\emph{Total work hours:} & \displaytime{\thehours:\theminutes}\\
\end{tabular}
}

% prints time and advances time counters, format is \tasktime{hh:mm}
\def\tasktime#1{\@tasktime#1::\@nil}
\def\@tasktime#1:#2:#3\@nil{%
    % add hours time to counter
    \setcounter{dailytime}{\thedailytime+#1*60}
    % if there are no minutes, detokenize is empty so \relax=\relax
    % output hour/hours 
    \if\relax\detokenize{#2}\relax
        #1 hr\ifnum#1=\@ne\hphantom{s}\else s\fi
    \else
        % check if minutes are greater than 0
        \ifnum#2>0
            % add minutes to counter and output time
            \setcounter{dailytime}{\thedailytime+#2}
            #1 hr%
                \ifnum#1=\@ne
                % '\' is for spacing
                \else s\fi \ #2 mins
        % if the minutes are not greater than 0
        \else
            #1 hr\ifnum#1=\@ne\hphantom{s}\else s\fi
    \fi
    \fi}

% prints time but does not advance the time counters
\def\displaytime#1{\@displaytime#1::\@nil}
\def\@displaytime#1:#2:#3\@nil{%
    \if\relax\detokenize{#2}\relax
        #1 hr\ifnum#1=\@ne\hphantom{s}\else s\fi
    \else
        \ifnum#2>0
            #1 hr%
                \ifnum#1=\@ne
                \else s\fi \ #2 mins
        \else
            #1 hr\ifnum#1=\@ne\hphantom{s}\else s\fi
    \fi
    \fi}

\newcommand{\task}[2]{#1 & \tasktime{#2}\\}

\newenvironment{dayreport}[1]{%
    \section*{#1}
    \appto\totaltimerows{#1 & }
    \begin{tabular}{p{0.75\textwidth}r}
    \toprule
    Task                    &   Approximate time \\
    \midrule}{
    \bottomrule
    \setcounter{minutes}{\thedailytime-((\thedailytime/60)*60)}
    \setcounter{hours}{\thedailytime/60}
    \setcounter{totaltime}{\thetotaltime+\thedailytime}%
    \setcounter{dailytime}{0}%
    \emph{Total time:}  &   \displaytime{\thehours:\theminutes}\\
    \end{tabular}
    \xappto\totaltimerows{\displaytime{\thehours:\theminutes}\noexpand\\}   
}

相关内容