секунд
Для измерения прошедшего времени (в секундах) нам нужно:
- целое число, представляющее количество прошедших секунд и
- способ конвертировать такое целое число в пригодный для использования формат.
Целочисленное значение прошедших секунд:
Преобразовать такое целое число в пригодный для использования формат
Внутренний bash printf
может сделать это напрямую:
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
так же
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
но это не удастся в течение более 24 часов, поскольку мы на самом деле выводим время на стене, а не длительность:
$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24
Для любителей деталей, от bash-hackers.org :
%(FORMAT)T
выводит строку даты и времени, полученную в результате использования FORMAT в качестве строки формата для strftime(3)
. Связанный аргумент - это количество секунд с начала эпохи , или -1 (текущее время) или -2 (время запуска оболочки). Если соответствующий аргумент не указан, по умолчанию используется текущее время.
Так что вы можете просто позвонить, textifyDuration $elpasedseconds
где textifyDuration
еще одна реализация длительной печати:
textifyDuration() {
local duration=$1
local shiff=$duration
local secs=$((shiff % 60)); shiff=$((shiff / 60));
local mins=$((shiff % 60)); shiff=$((shiff / 60));
local hours=$shiff
local splur; if [ $secs -eq 1 ]; then splur=''; else splur='s'; fi
local mplur; if [ $mins -eq 1 ]; then mplur=''; else mplur='s'; fi
local hplur; if [ $hours -eq 1 ]; then hplur=''; else hplur='s'; fi
if [[ $hours -gt 0 ]]; then
txt="$hours hour$hplur, $mins minute$mplur, $secs second$splur"
elif [[ $mins -gt 0 ]]; then
txt="$mins minute$mplur, $secs second$splur"
else
txt="$secs second$splur"
fi
echo "$txt (from $duration seconds)"
}
Дата GNU.
Чтобы получить форматированное время, мы должны использовать внешний инструмент (GNU date) несколькими способами, чтобы получить почти годичный результат, включая наносекунды.
Математика внутри даты.
Нет необходимости во внешней арифметике, сделайте все за один шаг date
:
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Да, 0
в командной строке есть ноль. Необходимо.
Это предполагает, что вы можете изменить date +"%T"
команду на date +"%s"
команду, чтобы значения сохранялись (печатались) в считанные секунды.
Обратите внимание, что команда ограничена:
- Положительные значения
$StartDate
и $FinalDate
секунды.
- Значение в
$FinalDate
больше (позже), чем $StartDate
.
- Разница во времени меньше 24 часов.
- Вы принимаете формат вывода с часами, минутами и секундами. Очень легко изменить.
- Допустимо использовать время -u UTC. Чтобы избежать "DST" и местное время корректировки.
Если вы должны использовать 10:33:56
строку, ну, просто преобразуйте ее в секунды,
также, слово секунд может быть сокращено как сек:
string1="10:33:56"
string2="10:36:10"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"
Обратите внимание, что преобразование времени в секундах (как показано выше) относится к началу «этого» дня (сегодня).
Концепция может быть расширена до наносекунд, например:
string1="10:33:56.5400022"
string2="10:36:10.8800056"
StartDate=$(date -u -d "$string1" +"%s.%N")
FinalDate=$(date -u -d "$string2" +"%s.%N")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S.%N"
Если требуется рассчитать более длительную (до 364 дней) разницу во времени, мы должны использовать начало (некоторый) год в качестве справочного материала и значение формата %j
(номер дня в году):
Похожий на:
string1="+10 days 10:33:56.5400022"
string2="+35 days 10:36:10.8800056"
StartDate=$(date -u -d "2000/1/1 $string1" +"%s.%N")
FinalDate=$(date -u -d "2000/1/1 $string2" +"%s.%N")
date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N"
Output:
026 days 00:02:14.340003400
К сожалению, в этом случае нам нужно вручную вычесть 1
ОДИН из числа дней. Команда date рассматривает первый день года как 1. Не так сложно ...
a=( $(date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N") )
a[0]=$((10#${a[0]}-1)); echo "${a[@]}"
Использование большого количества секунд допустимо и задокументировано здесь:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date.
Дата занятости
Инструмент, используемый на небольших устройствах (очень маленький исполняемый файл для установки): Busybox.
Либо сделайте ссылку на busybox с названием date:
$ ln -s /bin/busybox date
Затем используйте его, вызвав его date
(поместите в каталог, включенный в PATH).
Или сделайте псевдоним как:
$ alias date='busybox date'
У даты Busybox есть приятная опция: -D, чтобы получить формат ввода времени. Это открывает много форматов, которые будут использоваться как время. Используя опцию -D, мы можем напрямую преобразовать время 10:33:56:
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
И как вы можете видеть из вывода Команды выше, день считается «сегодняшним». Чтобы узнать время начала эпохи:
$ string1="10:33:56"
$ date -u -D "%Y.%m.%d-%H:%M:%S" -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Дата Busybox может даже получить время (в формате выше) без -D:
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
И формат вывода может быть даже секунды с начала эпохи.
$ date -u -d "1970.01.01-$string1" +"%s"
52436
Для обоих раз и немного bash math (busybox не может сделать математику, пока):
string1="10:33:56"
string2="10:36:10"
t1=$(date -u -d "1970.01.01-$string1" +"%s")
t2=$(date -u -d "1970.01.01-$string2" +"%s")
echo $(( t2 - t1 ))
Или в формате:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
time
команду?