Como produzir uma data / hora como “20 minutos atrás” ou “9 dias atrás”, etc.

4

Eu executo rsync como um trabalho cron e exibo o último backup via conky (ou seja, "Último backup 2017 05 12 14:22:20" ). Gostaria de exibir meu último backup como "2 dias atrás" ou "4 horas atrás" , em vez de exibir apenas um registro de data estático.

Existe alguma maneira de exibir uma data / hora usando esse tipo de formato de saída amigável? Eu olhei para man date , mas não consigo encontrar nada sobre a saída de uma data nesse tipo de formato. Eu vejo como consultar uma hora ou data relativa com o sinal -d , mas não consigo ver como obter a saída de data para incluir palavras como "ontem" , "há 3 dias" etc .

Obrigado!

    
por Aijalon 13.05.2017 / 02:31

5 respostas

2

usando bash você pode fazer algo parecido com o código abaixo:
Note que você precisará usar sed ou algo para reformatar sua string de data para algo que date aceitará, como:

"2017-05-13 15:44:20"
#!/usr/bin/env bash

last_run="2017-05-13 15:44:20"


function relative() {
    local last_unix="$(date --date="$1" +%s)"    # convert date to unix timestamp
    local now_unix="$(date +'%s')"

    local delta=$(( $now_unix - $last_unix ))

    if (( $delta < 60 )) 
    then
        echo "last run "$delta" seconds ago"
        return 
    elif ((delta < 2700))  # 45 * 60
    then
        echo "last run "$(( $delta / 60 ))" minutes ago";
    fi
}

relative "$last_run"
    
por 13.05.2017 / 05:50
2

Aqui está uma extensão da resposta do the_velour_fog, adaptada para usar segundo / minuto / dia / mês / ano.

#!/usr/bin/env bash

last_run="2018-06-21T21:10:18-06:00"


function rel_fmt_low_precision() {
    local SEC_PER_MINUTE=$((60))
    local   SEC_PER_HOUR=$((60*60))
    local    SEC_PER_DAY=$((60*60*24))
    local  SEC_PER_MONTH=$((60*60*24*30))
    local   SEC_PER_YEAR=$((60*60*24*365))

    local last_unix="$(date --date="$1" +%s)"    # convert date to unix timestamp
    local now_unix="$(date +'%s')"

    local delta_s=$(( now_unix - last_unix ))

    if (( delta_s <  SEC_PER_MINUTE * 2))
    then
        echo "last run "$((delta_s))" seconds ago"
        return 
    elif (( delta_s <  SEC_PER_HOUR * 2))
    then
        echo "last run "$((delta_s / SEC_PER_MINUTE))" minutes ago"
        return 
    elif (( delta_s <  SEC_PER_DAY * 2))
    then
        echo "last run "$((delta_s / SEC_PER_HOUR))" hours ago"
        return 
    elif (( delta_s <  SEC_PER_MONTH * 2))
    then
        echo "last run "$((delta_s / SEC_PER_DAY))" days ago"
        return 
    elif (( delta_s <  SEC_PER_YEAR * 2))
    then
        echo "last run "$((delta_s / SEC_PER_MONTH))" months ago"
        return 
    else
        echo "last run "$((delta_s / SEC_PER_YEAR))" years ago"
        return 
    fi
}

rel_fmt_low_precision "'date'"
rel_fmt_low_precision "2018-06-21 21:10:18"
rel_fmt_low_precision "2018-06-21 20:10:18"
rel_fmt_low_precision "2018-05-21 21:10:18"
rel_fmt_low_precision "2017-06-21 20:10:18"
rel_fmt_low_precision "2016-06-21 20:10:18"

Veja como ele decide qual unidade usar: ele usa a maior unidade que fornece um número de pelo menos dois.

Exemplo: se algo aconteceu 72 horas atrás, a saída será em dias. Se algo aconteceu exatamente há uma hora, ele usará minutos.

    
por 22.06.2018 / 05:26
2

Espero que alguém tenha uma solução melhor, mas aqui está um script que eu criei:

#!/bin/sh
cd /tmp
git init -q
git -c user.email=0 -c user.name=0 commit -q -m 0 --allow-empty --date="$1"
git show --format=%ar

Resultado:

$ relative.sh 2016-1-23
2 years, 5 months ago

$ relative.sh 2016-9-23
1 year, 9 months ago
    
por 23.06.2018 / 03:45
1

Usando awk :

hdate () {
  awk -v date="$(date +%s -d "$1")" -v now="$(date +%s)" '
    BEGIN {  diff = now - date;
       if (diff > (24*60*60)) printf "%.0f days ago", diff/(24*60*60);
       else if (diff > (60*60)) printf "%.0f hours ago", diff/(60*60);
       else if (diff > 60) printf "%.0f minutes ago", diff/60;
       else printf "%s seconds ago", diff;
    }'
}

Exemplo:

~$ hdate '2018-06-17 14:22:20'
5 days ago

A data de entrada deve estar no formato date pode ler.

    
por 22.06.2018 / 10:30
0

Bem na linguagem Perl (do Perl Cookbook ) você iria:

use Date::Calc qw(Delta_DHMS);
@now = ( 1981, 6, 16, 4, 35, 25 ); # 16 June 1981 4:35:25
@then =( 1973, 1, 18, 3, 45, 50 ); # 18 January 1973 3:45:50

@diff = Delta_DHMS( @then, @now );

print "This is now, then was $diff[0] days, $diff[1]:$diff[2]:$diff[3] ago!\n";

E obtenha:

This is now, then was 3071 days, 0:49:35 ago!

Infelizmente, o módulo Date::Calc não está instalado por padrão, portanto, é necessário obter alguém para instalá-lo ou aprender a usar o próprio gerenciador de módulos do Perl, o CPAN.

    
por 13.05.2017 / 03:55