Арифметические операции с HH: MM: SS раз в пакетном файле

В одном из моих пакетных скриптов мне нужно рассчитать продолжительность интервала в видеофайле. Сначала пользователю предлагается ввести время начала и окончания:

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

Затем я хотел бы, чтобы пакет script вычислял продолжительность между ними.

Как я могу вычесть %StartPosition% из %EndPosition% следующим образом, например:

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

Причина, по которой я не могу понять, как это сделать, состоит в том, что эти числа разделены двоеточиями.

Изменить: этот вопрос отличается от этого вопроса, потому что мне не нужен скрипт для обработки чисел как значений времени.

Ответ 1

@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%

EDIT: добавлены некоторые пояснения

Эта программа использует обычный метод для преобразования времени в формате HH: MM: SS на несколько секунд по стандартной формуле: seconds = (HH*60+MM)*60+SS. Однако команда set /A рассматривает числа, начинающиеся с 0, как написано в восьмеричной базе, и, следовательно, 08 и 09 будут недопустимыми восьмеричными числами. Чтобы избежать этой проблемы, перед тем, как развернуть число, помечается цифра 1, а затем 100 вычитается, поэтому, если HH=08, то 1%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:30 и EndPosition=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=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

Ответ 2

Это можно сделать в чистой партии анализировать каждое поле как независимую строку, а затем делать арифметику на них. Многие практические решения заходят в какую-то другую программу, чтобы выполнить математику по дате.

Следующий код вызывает 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 и вычесть их, а другой - для вывода результата в указанном вами формате.

Ответ 3

Здесь рабочий прототип:

@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

Это не полный, но разумный старт.

Ответ 4

Я думаю, @Aacini очистил все здесь. Он достал тебя, прежде чем я сделаю. Но я хочу улучшить его как - используя Для цикла, чтобы сделать код проще.

Примечание: Все после < REM "- комментарий для понимания легко...
Все, что вам нужно сделать, это скопировать его в ваш пакетный файл. И используйте его следующим образом (в вашем основном коде):

Синтаксис: Вызов: время [ваше время 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 - 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) Вы найдете много всего там - чтобы помочь вам.:) Здесь Конечный вывод - Когда я сохранил код в файле ответа .bat