Вопрос или проблема
У меня есть дата, которая, как я знаю, всегда будет в будущем хотя бы на одну секунду.
Затем я вычисляю разницу между текущей датой и целевой датой в секундах.
Но я не могу понять, как отобразить разницу в секундах в удобочитаемом формате с помощью date
.
Я пытаюсь конвертировать секунды таким образом:
56 -> через 56 секунд
325 -> через 5 минут 25 секунд
3613 -> через 1 час 13 секунд
345603 -> через 4 дня 3 секунды
Я не хочу выходить за пределы значения “дней”, и я не хочу отображать значение, если оно 0
.
Есть ли способ сделать это с помощью date
? Или мне следует делать расчеты самостоятельно в bash?
Я пробовал:
date --utc -d @"$seconds" +"%-dd %-Hh %-Mm %-Ss"
Но есть две проблемы с этим подходом: во-первых, значение дней неверно, во-вторых, это будет отображать значение даже когда оно 0
.
#!/bin/bash
reldate() {
local remains=$1
set -- second s 60 minut es 60 hour s 24 day s 0
local date=""
while (($#)) ; do
local unit=$1
local plural=$2
local n=$3
shift 3
local amount=$remains
(( n )) && (( amount %= n ))
if ((amount)) ; then
(( amount > 1 )) && unit+=$plural
date="$amount $unit $date"
(( remains -= amount ))
fi
(( n )) && (( remains /= n ))
done
printf 'через %s' "${date% }"
}
set -eu
[[ $(reldate 56) == 'через 56 секунд' ]]
[[ $(reldate 325) == 'через 5 минут 25 секунд' ]]
[[ $(reldate 3613) == 'через 1 час 13 секунд' ]]
[[ $(reldate 345603) == 'через 4 дня 3 секунды' ]]
[[ $(reldate 349203) == 'через 4 дня 1 час 3 секунды' ]]
[[ $(reldate 63072000) == 'через 730 дней' ]]
[[ $(reldate 63071999) == 'через 729 дней 23 часа 59 минут 59 секунд' ]]
Слово, которое я искал, было “продолжительность”.
Вот решения, которые я нашел после того, как понял это:
Добавьте код ниже к одному из приведенных выше решений, чтобы решить эту проблему:
| sed 's/0[a-z] //g
Ответ или решение
Чтобы отобразить разницу во времени в читаемом формате на основе секунд, вы можете создать функцию на Bash, которая разбивает значение секунд на более понятные единицы времени, такие как дни, часы, минуты и секунды. Это позволит вам избежать использования лишних значений и сосредоточиться только на значимых единицах времени.
В приведённом примере ниже показано, как можно реализовать решение, соответствующее вашим требованиям:
#!/bin/bash
reldate() {
local remains=$1
set -- second s 60 minute s 60 hour s 24 day s 0
local date=""
while (($#)); do
local unit=$1
local plural=$2
local n=$3
shift 3
local amount=$remains
(( n )) && (( amount %= n ))
if (( amount )); then
(( amount > 1 )) && unit+=$plural
date="$amount $unit $date"
(( remains -= amount ))
fi
(( n )) && (( remains /= n ))
done
printf 'in %s' "${date% }"
}
set -eu
# Примеры использования функции
echo $(reldate 56)
echo $(reldate 325)
echo $(reldate 3613)
echo $(reldate 345603)
echo $(reldate 349203)
Как это работает:
-
Функция
reldate
:- Принимает количество секунд в качестве аргумента.
- Использует команду
set
для определения, как переводить секунды в более крупные единицы времени. - В цикле проверяет каждую единицу времени и добавляет её к результирующей строке, если значение больше нуля.
-
Форматирование вывода:
- Функция создает строку, которая отображает время в нужном формате, исключая единицы, равные нулю.
Тестирование:
Функция тестируется на различных значениях секунд, чтобы убедиться, что вывод соответствует ожидаемому формату. Обратите внимание на то, что вывод обрезается, где это необходимо.
Устранение ненужных значений:
Если в вашем выводе по-прежнему появляются нулевые значения, вы можете использовать sed
, чтобы убрать их:
| sed 's/0[a-z] //g'
Примеры результатов:
reldate 56
выдастin 56 seconds
reldate 325
выдастin 5 minutes 25 seconds
reldate 3613
выдастin 1 hour 13 seconds
reldate 345603
выдастin 4 days 3 seconds
reldate 349203
выдастin 4 days 1 hour 3 seconds
Заключение:
Используя предложенный подход, вы сможете с легкостью отображать разницу во времени в читаемом формате, избегая лишних единиц измерения. Этот метод предоставляет гибкость и контроль, а также позначает отличную пример того, как Bash может быть использован для решения повседневных задач.