Отобразите относительную дату с помощью date в удобочитаемом формате.

Вопрос или проблема

У меня есть дата, которая, как я знаю, всегда будет в будущем хотя бы на одну секунду.

Затем я вычисляю разницу между текущей датой и целевой датой в секундах.

Но я не могу понять, как отобразить разницу в секундах в удобочитаемом формате с помощью 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)

Как это работает:

  1. Функция reldate:

    • Принимает количество секунд в качестве аргумента.
    • Использует команду set для определения, как переводить секунды в более крупные единицы времени.
    • В цикле проверяет каждую единицу времени и добавляет её к результирующей строке, если значение больше нуля.
  2. Форматирование вывода:

    • Функция создает строку, которая отображает время в нужном формате, исключая единицы, равные нулю.

Тестирование:

Функция тестируется на различных значениях секунд, чтобы убедиться, что вывод соответствует ожидаемому формату. Обратите внимание на то, что вывод обрезается, где это необходимо.

Устранение ненужных значений:

Если в вашем выводе по-прежнему появляются нулевые значения, вы можете использовать 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 может быть использован для решения повседневных задач.

Оцените материал
Добавить комментарий

Капча загружается...