Секунди
Для вимірювання минулого часу (у секундах) нам потрібно:
- ціле число, яке представляє кількість пройдених секунд і
- спосіб конвертувати таке ціле число у придатний формат.
Ціле значення минулих секунд:
Перетворити таке ціле число у придатний формат
Баш внутрішній 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)
. Асоційованим аргументом є кількість секунд після Epoch , або -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 -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Так, є 0
у командному рядку нуль. Це потрібно.
Це припускаючи, що ви можете змінити date +"%T"
команду на adate +"%s"
команду, щоб значення зберігалися (друкувалися) у секундах.
Зауважте, що команда обмежена:
- Позитивні значення
$StartDate
і $FinalDate
секунди.
- Значення в
$FinalDate
є більшим (пізніший час), ніж $StartDate
.
- Різниця в часі менше 24 годин.
- Ви приймаєте формат виводу за допомогою годин, хвилин і секунд. Дуже легко змінити.
- Прийнятно використовувати -у UTC раз. Щоб уникнути "DST" та місцевих корекцій часу.
Якщо ви повинні використовувати 10:33:56
рядок, ну просто перетворіть його на секунди,
також слово секунди може бути скорочено як sec:
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
ОДНО від кількості днів. Команда дати побачить перший день року як 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.
Або зробіть посилання на зайняту скриньку під назвою дата:
$ ln -s /bin/busybox date
Використовуйте його, зателефонувавши до цього date
(помістіть його у каталог, включений у PATH).
Або зробіть псевдонім на зразок:
$ alias date='busybox date'
Дата зайнятої скриньки має хороший варіант: -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
Дата зайнятої скриньки навіть може отримати час (у форматі вище) без -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
І для обох разів, і для невеликої математики (зайнятий ще не може зробити математику):
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
команду?