在批处理文件中使用HH:MM:SS的算术运算

时间:2017-03-05 00:44:22

标签: batch-file cmd

在我的一个批处理脚本中,我需要计算视频文件中间隔的持续时间。首先要求用户输入开始和结束时间:

%StartPosition%

然后,我希望批处理脚本能够计算两者之间的持续时间。

如何从%EndPosition%这样减去{{1}},例如:

  

00:10:40 - 00:10:30 = 00:00:10

我无法弄清楚如何做到这一点的原因是因为这些数字是以冒号分隔的。

编辑:此问题与this问题不同,因为我不需要使用脚本将数字视为时间值。

4 个答案:

答案 0 :(得分:6)

@echo off
setlocal

set /p "StartPosition=Start position (HH:MM:SS): "
set /p "EndPosition=End position (HH:MM:SS):   "

set /A "ss=(((1%EndPosition::=-100)*60+1%-100)-(((1%StartPosition::=-100)*60+1%-100)"
set /A "hh=ss/3600+100,ss%%=3600,mm=ss/60+100,ss=ss%%60+100"

echo Duration=%hh:~1%:%mm:~1%:%ss:~1%

编辑添加了一些解释

此程序使用通常的方法通过标准公式{H}:MM:SS格式将时间转换为秒数:seconds = (HH*60+MM)*60+SS。但是,set /A命令会考虑以八进制基础中所写的0开头的数字,因此0809将是无效的八进制数字。为避免此问题,在展开数字之前放置一个数字1,之后减去100,因此如果HH=081%HH%-100正确地给出8;那就是:

set /A seconds = ((1%HH%-100)*60+1%MM%-100)*60+1%SS%-100

有几种方法可以将HH:MM:SS格式中给出的时间分成三部分。例如,如果我们以set EndPosition=HH:MM:SS为基础,那么我们可以这样使用for /F命令:

for /F "tokens=1-3 delims=:" %%a in ("%EndPosition%") do (
   set /A "seconds=((1%%a-100)*60+1%%b-100)*60+1%%c-100"
)

在此程序中使用了不同的方法。如果我们将原始EndPosition=HH:MM:SS字符串与所需的公式匹配,我们可以构建此映射方案:

     HH       :      MM       :      SS

((1  HH  -100)*60+1  MM  -100)*60+1  SS  -100

换句话说:如果我们-100)*60+1替换原始字符串的冒号并在开头插入((1并在结尾插入-100,我们获取期望的配方;那就是:

set /A "seconds=((1%EndPosition::=-100)*60+1%-100"

这是一种非常有效的方法,甚至允许在同一公式中替换EndPosition和StartPosition字符串(将两个部分括在括号中)并直接减去它们:

set /A "ss=(((1%EndPosition::=-100)*60+1%-100)-(((1%StartPosition::=-100)*60+1%-100)"

您可以取消@echo off命令并运行程序以查看替换变量值后评估的确切公式。例如,当StartPosition=00:10:30EndPosition=00:10:40时,这是评估的表达式:

set /A "ss=(((100-100)*60+110-100)*60+140-100)-(((100-100)*60+110-100)*60+130-100)"

只是为了完成这个描述,这是"标准"使用for /F命令评估相同公式的方法:

for /F "tokens=1-6 delims=:" %%a in ("%EndPosition%:%StartPosition%") do (
   set /A "ss=(((1%%a-100)*60+1%%b-100)*60+1%%c-100)-(((1%%d-100)*60+1%%e-100)*60+1%%f-100)"
)

从秒数到HH:MM:SS部分的相反转换很简单:

HH=SS/3600, rest=SS%3600, MM=rest/60, SS=rest%60

但是,结果中的每个部分必须以两位数显示,但这种格式化可以通过非常简单的方式实现。在这种情况下,不是插入三个if命令来检查每个部分是否小于10并插入填充零,而是将100添加到部件中(转换8例如,进入108,并且当显示每个部分时,省略第一个数字(因此仅显示08)。这是一种非常有效的格式化数字的方法,可以在用于获取部件的相同set /A命令中执行。例如:

set /A "hh=ss/3600+100,ss%%=3600,mm=ss/60+100,ss=ss%%60+100"

echo Duration=%hh:~1%:%mm:~1%:%ss:~1%

通过这种方式,将两次转换为两个秒,它们的减法和相反的转换以及格式化为HH:MM:SS在两个SET / A命令中执行,即使是可以写成一个长长的行。

输出示例:

Start position (HH:MM:SS): 00:10:30
End position (HH:MM:SS):   00:10:40
Duration=00:00:10

Start position (HH:MM:SS): 00:10:45
End position (HH:MM:SS):   00:11:05
Duration=00:00:20

答案 1 :(得分:0)

这可以通过parsing each field as an independent string, then doing arithmetic on them以纯批量进行。许多practical solutions调用其他程序来进行日期数学运算。

以下代码调用PowerShell以使用.NET DateTime类为您进行解析。

C:\> set "StartPosition=00:10:30"
C:\> set "EndPosition=00:10:40"
C:\> PowerShell.exe -c "$span=([datetime]'%EndPosition%' - [datetime]'%StartPosition%'); '{0:00}:{1:00}:{2:00}' -f $span.Hours, $span.Minutes, $span.Seconds"
00:00:10

执行两行PowerShell代码;一个将两个时间转换为DateTime个对象并减去它们,另一个以您指定的格式输出结果。

答案 2 :(得分:0)

这是一个工作原型:

@echo off 

set T1=00:10:45
set T2=00:11:05

set HOUR1=%T1:~,2%
set MIN1=%T1:~3,-3%
set SEC1=%T1:~-2%

set HOUR2=%T2:~,2%
set MIN2=%T2:~3,-3%
set SEC2=%T2:~-2%

set /A TOTAL_SEC1=%HOUR1%*3600+%MIN1%*60+SEC1
set /A TOTAL_SEC2=%HOUR2%*3600+%MIN2%*60+SEC2
set /A DIFF=%TOTAL_SEC2%-%TOTAL_SEC1%

echo %DIFF%

<强>输出:

20

它不完整,但它是一个合理的开始。

答案 3 :(得分:0)

我想, @Aacini 已经清除了这里的一切。在我做之前,他找到了你。但是,我希望改进他 - 通过使用 For Loop 来使代码更容易。

注意:&#39; REM &#39;之后的所有内容是为了便于理解的评论...
您需要做的就是将其复制到批处理文件中。并且,使用如下(在您的主要代码中):

语法:通话:时间[您的时间1] [操作] [您的时间2]

并且,您现在可以申请 - 任何操作 - 包括“添加,减少,划分,乘法”等。 ;)       时间函数
    --------------复制以下代码----------

:Time [Start_Time] [Operation] [End_Time]
SetLocal EnableDelayedExpansion
REM Creating a portable Function for your Job. :)

REM Reading Start-time...
For /F "Tokens=1,2,3 Delims=:" %%A in ("%~1") Do (
Set _Start_Hour=%%A
Set _Start_Min=%%B
Set _Start_Sec=%%C
)

REM Reading End-time...
For /F "Tokens=1,2,3 Delims=:" %%A in ("%~3") Do (
Set _End_Hour=%%A
Set _End_Min=%%B
Set _End_Sec=%%C
)

REM Removing leading Zero's - if any... 'CMD assumes it as octal - otherwise'
For %%A In (Hour Min Sec) Do (
    For %%B In (Start End) Do (
        IF /I "!_%%B_%%A:~0,1!" == "0" (Set _%%B_%%A=!_%%B_%%A:~1!)
        )
)

REM Applying Operation on the given times.
For %%A In (Hour Min Sec) Do (Set /A _Final_%%A=!_Start_%%A! %~2 !_End_%%A!)

REM Handling a little Exceptional errors! - due to the nature of time (60 sec for a min.)
SET _Extra_Hour=0
SET _Extra_Min=0

REM Two Cases can arise in each part of time...
:Sec_loop
IF %_Final_Sec% GTR 59 (Set /A _Extra_Min+=1 & Set /A _Final_Sec-=60 & Goto :Sec_loop)
IF %_Final_Sec% LSS 0 (Set /A _Extra_Min-=1 & Set /A _Final_Sec+=60 & Goto :Sec_loop)

Set /A _Final_Min+=%_Extra_Min%

:Min_loop
IF %_Final_Min% GTR 59 (Set /A _Extra_Hour+=1 & Set /A _Final_Min-=60 & Goto :Min_loop)
IF %_Final_Min% LSS 0 (Set /A _Extra_Hour-=1 & Set /A _Final_Min+=60 & Goto :Min_loop)

Set /A _Final_Hour+=%_Extra_Hour%

REM Saving Everything into a Single Variable - string.
Set _Final_Time=%_Final_Hour%:%_Final_Min%:%_Final_Sec%

REM Displaying it on the console. ;)
Echo.%_Final_Time%
Goto :EOF
--------------End OF Code----------------------

您还可以访问我的网站 - 基于批量编程。 (www.thebateam.org)你会在那里找到很多东西 - 帮助你。 :) Here's the Final Output - When I saved the Code in Answer.bat File