我想计算时间差。
例如:
- 22:44 - 22:50 -> 00:06
- 23:00 — 00:10 -> 01:10
在第二种情况下,时间隐含地是第二天。
我的想法是:
- 将时间转换为总分钟数(h*60+m)。
- 计算差异。
- 将差异转换回格式
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}