\def 语法问题

\def 语法问题

我想计算时间差。

例如:

  • 22:44 - 22:50 -> 00:06
  • 23:00 — 00:10 -> 01:10

在第二种情况下,时间隐含地是第二天。

我的想法是:

  1. 将时间转换为总分钟数(h*60+m)。
  2. 计算差异。
  3. 将差异转换回格式hh:mm

目前,我遇到了一个语法错误:

缺少的数字,视为零。表达式中插入缺少的 )。

\documentclass{article}

\def\nok#1:#2\relax#3:#4\relax{%
    \def\tStart{\the\numexpr(#1*60+#2)}%
    \def\tEnd{\the\numexpr(#3*60+#4)}%
    \tEnd\ifnum\tEnd<\tStart+1440\fi%
}

\begin{document}

\the\numexpr(\nok22:44\relax22:50\relax)

\end{document}

我究竟做错了什么?

答案1

一种不使用包裹的方法。

\documentclass{article}


\makeatletter
% Will be expandable, expands in two steps
\newcommand{\timedelta}[2]{\romannumeral0\timedelta@i#1:#2:}%
% get arguments and evaluate time difference in minutes
\def\timedelta@i #1:#2:#3:#4:%
   {\expandafter\timedelta@ii\the\numexpr#3*60+#4-#1*60-#2.}%
% correct modulo 24*60 if difference turns out negative
\def\timedelta@ii#1{\expandafter\timedelta@iii\the\numexpr
                    \if-#11440\fi #1}%
% do Euclidean division by 60. Curse \numexpr rounding in passing.
\def\timedelta@iii#1.{\expandafter\timedelta@iv\the\numexpr
                    (#1 + 30)/60 -1.#1.}%
% Get the remainder too, prepare for zero padding
\def\timedelta@iv #1.#2.{\expandafter\timedelta@v\the\numexpr
                    100+#2-60*#1\expandafter.\the\numexpr100+#1.}
% Output final result 
\def\timedelta@v 1#1.1#2.{ #2:#1}
\makeatother

\begin{document}

\timedelta{22:40}{22:50}

\timedelta{23:00}{00:10}

\timedelta{08:24}{19:32}

\end{document}

在此处输入图片描述


在实践中,人们可能希望使用\timedelta参数本身就是宏的函数。但上面的代码并没有扩展参数。这引出了后续问题可能只是另一个 gdef 扩展问题

我提供了一个回答它通过生成扩展其参数的变体来完成上述代码。

让我在这里简单地扩展上面的代码,以便\timedelta自动扩展它的两个参数。这种扩展将是所谓的“完整(第一个标记)扩展”,特别是\timedelta可以用作自身的参数,以便可以计算 delta 的 delta 等……就像牛顿迭代差分一样。以防您闲置一段时间。

\documentclass{article}    

\makeatletter
% Will be expandable, expands in two steps

% Expands its arguments!

\newcommand{\timedelta}[2]%
  {\romannumeral0\expandafter\timedelta@h\expandafter
     {\romannumeral-`0#2}{#1}}%
\def\timedelta@h #1#2{\expandafter\timedelta@i\romannumeral-`0#2:#1:}

% get arguments and evaluate time difference in minutes
\def\timedelta@i #1:#2:#3:#4:%
   {\expandafter\timedelta@ii\the\numexpr#3*60+#4-#1*60-#2.}%
% correct modulo 24*60 if difference turns out negative
\def\timedelta@ii#1{\expandafter\timedelta@iii\the\numexpr
                    \if-#11440\fi #1}%
% do Euclidean division by 60. Curse \numexpr rounding in passing.
\def\timedelta@iii#1.{\expandafter\timedelta@iv\the\numexpr
                    (#1 + 30)/60 -1.#1.}%
% Get the remainder too, prepare for zero padding
\def\timedelta@iv #1.#2.{\expandafter\timedelta@v\the\numexpr
                    100+#2-60*#1\expandafter.\the\numexpr100+#1.}
% Output final result 
\def\timedelta@v 1#1.1#2.{ #2:#1}
\makeatother

\begin{document}

\timedelta{22:40}{22:50}

\timedelta{23:00}{00:10}

\timedelta{08:24}{19:32}

\newcommand\timeStart{00:02}
\newcommand\timeEnd{00:01}

\timedelta{\timeStart}{\timeEnd}

\timedelta{\timeEnd}{\timeStart}

\timedelta{\timedelta{10:00}{14:23}}{\timedelta{10:00}{14:22}}

\end{document}

在此处输入图片描述

答案2

\numexpr表达式必须扩张到数字语法,这样你就不能有不可扩展的分配\def

我认为这是你想要的计算

\documentclass{article}

\def\nok#1:#2\relax#3:#4\relax{%
\numexpr
 \numexpr(#3)*60+#4\relax
 \ifnum\numexpr(#1)*60+#2\relax<\numexpr(#1)*60+#2\relax+1440\fi
\relax
 }

\begin{document}

\the\numexpr(\nok22:44\relax22:50\relax)\relax

\end{document}

答案3

如果您愿意使用lualatex而不是进行编译,您也可以使用 Lua pdflatex

输出

\documentclass{article}

\directlua{dofile('timediff.lua')}
\def\wait#1#2{\directlua{tex.print(timediff('#1', '#2'))}}

\begin{document}
The time from 22:44 to 22:50 is \wait{22:44}{22:50}.

The time from 23:00 to 00:10 is \wait{23:00}{00:10}.
\end{document}

哪里timediff.lua

function hhms(s)
   -- Example: hhms('01:42') gives 102
   local _, _, hh, mm = string.find(s, "(%d*):(%d*)")
   return hh * 60 + mm
end

function timediff(time1, time2)
   -- Example: timediff('22:45', '01:15') gives '02:30'
   local t1 = hhms(time1)
   local t2 = hhms(time2)
   if t2 < t1 then t2 = t2 + 1440 end
   local d = t2 - t1
   local mm = d % 60
   local hh = (d - mm) / 60
   return string.format('%02d:%02d', hh, mm)
end

稍后你可能会发现 Lua 的时间和日期有用的功能。

答案4

以下假设时间的形式为HH:MM

在此处输入图片描述

\documentclass{article}

\usepackage{xfp}

\makeatletter

\def\TheHour#1:#2@END{#1}
\def\TheMinute#1:#2@END{#2}

\newcommand{\timediff}[2]{%
  \two@digits{% HOUR
    \fpeval{(\TheHour#2@END)-(\TheHour#1@END)% Hour difference
            +(\ifnum\TheHour#2@END<\TheHour#1@END 24\else 0\fi)% Correction for time spanning midnight
            -(\ifnum\TheMinute#2@END<\TheMinute#1@END 1\else 0\fi)}% Minute correction
  }%
  {:}%
  \two@digits{% MINUTE
    \fpeval{(\TheMinute#2@END)-(\TheMinute#1@END)% Minute difference
            +(\ifnum\TheMinute#2@END<\TheMinute#1@END 60\else 0\fi)}% Minute correction
  }%
}
\makeatother

\begin{document}

$22{:}44 - 22{:}50 = \timediff{22:44}{22:50}$

$23{:}00 - 00{:}10 = \timediff{23:00}{00:10}$

$00{:}00 - 23{:}59 = \timediff{00:00}{23:59}$

$22{:}44 - 00{:}43 = \timediff{22:44}{00:43}$

$12{:}34 - 12{:}34 = \timediff{12:34}{12:34}$

\end{document}

相关内容