Como converter carimbos de data e hora em datas no Bash?

270

Eu preciso de um comando ou script de shell que converta um carimbo de data e hora do Unix em uma data. A entrada pode vir do primeiro parâmetro ou do stdin, permitindo os seguintes padrões de uso:

ts2date 1267619929

e

echo 1267619929 | ts2date

Ambos os comandos devem gerar "Wed 3 de março 13:38:49 2010".

Chiborg
fonte

Respostas:

532

Nas versões posteriores de distribuições comuns do Linux, você pode usar:

date -d @1267619929
a'r
fonte
5
Uma linha:date -d @$(date -u +%s)
Mike Atlas
26
Para que serve @? Não vejo isso na página de manual do GNU.
Mark E. Haase
13
@mehaase - a página de manual observa que a sequência de datas é muito complexa para ser documentada na página de manual, portanto, é descrita em info: info '(coreutils) data invocation' #
MByD 23/03/16
10
brew install coreutils; gdate -d @1267619929
Mark Fox
2
info 'Date input formats' leva você diretamente ao datenó de informações de formatação, com a citação pertinente de Robert Grudin e, em seguida, um menu de especificadores de formato.
Mike
165
date -r <number>

funciona para mim no Mac OS X.

rafaelzlisboa
fonte
5
Sim, mas não lida com frações de segundo.
MGold
1
E é confuso porque não está funcionando dessa maneira na maioria dos sistemas Linux, porque: freddy @ hades ~% date --help | grep - -r -r, --reference = mostrador o último tempo de modificação de ARQ
frank42
1
embora os comentários sobre essa resposta sejam verdadeiros, a culpa não é de rafa e não diminui a resposta dele.
Mike19
29

Esta versão é semelhante à resposta de chiborg , mas elimina a necessidade de informações externas ttye cat. Ele usa date, mas poderia usar com a mesma facilidade gawk. Você pode alterar o shebang e substituir os colchetes duplos por simples e isso também ocorrerá sh.

#!/bin/bash
LANG=C
if [[ -z "$1" ]]
then
    if [[ -p /dev/stdin ]]    # input from a pipe
    then
        read -r p
    else
        echo "No timestamp given." >&2
        exit
    fi
else
    p=$1
fi
date -d "@$p" +%c
Pausado até novo aviso.
fonte
+1: resposta muito completa e acho que a data é mais rápida que o gawk.
de Bruno Brant
@ Bruno, como você sabe que a data é mais rápida que o gawk.?
ghostdog74
3
@Bruno, @ ghostdog74: No meu sistema, gawké (aproximadamente) 15% mais rápido do que dateem um forloop cronometrado que consiste apenas de gawk 'BEGIN { print strftime("%c", 1256571985); }'ou date -d '@1256571985' +%ccom saída redirecionada para /dev/null.
Pausado até novo aviso.
1
date é marginalmente (5%) mais rápido do que o gawk para mim (mac osx 10.9.2, data 8.23, gawk 4.1.1), mas a vantagem real do (g) awk é aceitar um pipe de uma coluna com muitos registros de data e hora (consulte minha resposta abaixo), que torna o script, por exemplo, 250x mais rápido para 1000 registros de data e hora.
Webb
3
Observe que minha resposta atende aos requisitos do OP, conforme indicado na pergunta, mas a resposta agora aceita não.
Pausado até novo aviso.
17

Você pode usar a data GNU, por exemplo,

$ sec=1267619929
$ date -d "UTC 1970-01-01 $sec secs"

ou

$ date -ud @1267619929
ghostdog74
fonte
10

Você pode usar este script awk simples:

#!/bin/gawk -f   
{ print strftime("%c", $0); }

Uso da amostra:

$ echo '1098181096' | ./a.awk 
Tue 19 Oct 2004 03:18:16 AM PDT
$
codaddict
fonte
Isso não se encaixa no primeiro uso - às vezes não quero fazer eco do TS e usar um parâmetro.
chiborg
Em alguma versão antiga do busybox, date -s @ não funciona e awkainda funciona! Um exemplo sem um stdin também seria útil.
Victor Sergienko 31/01
8

Desde o Bash 4.2, você pode usar printfo %(datefmt)Tformato:

$ printf '%(%c)T\n' 1267619929
Wed 03 Mar 2010 01:38:49 PM CET

Isso é legal, porque é um shell embutido. O formato para datefmt é uma sequência aceita por strftime(3)(consulte man 3 strftime). Aqui %cestá:

%c A representação preferida de data e hora para o código do idioma atual.


Agora, se você deseja um script que aceite um argumento e, se nenhum for fornecido, lê stdin, poderá prosseguir como:

#!/bin/bash

if (($#)); then
    printf '%(%c)T\n' "$@"
else
    while read -r line; do
        printf '%(%c)T\n' "$line"
    done
fi
gniourf_gniourf
fonte
6

Eu uso isso ao converter arquivos de log ou monitorá-los:

tail -f <log file> | gawk \
'{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }'
user3544224
fonte
exatamente o que eu estava procurando, pode ser encurtado paraawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue
5

No OSX, ou BSD, há um -rsinalizador equivalente que aparentemente leva um timestamp unix. Aqui está um exemplo que executa a data quatro vezes: uma vez na primeira data, para mostrar o que é; um para a conversão em carimbo de data / hora unix %se, finalmente, um que, com -r, converte o que %sfornece de volta em uma string.

$  date; date +%s; date -r `date +%s`
Tue Oct 24 16:27:42 CDT 2017
1508880462
Tue Oct 24 16:27:42 CDT 2017

Pelo menos, parece funcionar na minha máquina.

$ uname -a
Darwin XXX-XXXXXXXX 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 15 17:36:27 PDT 2017; root:xnu-3789.70.16~2/RELEASE_X86_64 x86_64
Daniel Farrell
fonte
Se você já tem um valor timestamp e você só precisa encontrar a data equivalente, no OS X, você pode simplesmente digitar isso na linha de comando: date -r 1509453417
Noel Whitemore
1
Isso é verdade. Se você olhar para a minha resposta, estou demonstrando isso.
Daniel Farrell
5

Você pode obter a data formatada a partir de timestamp como este

date +'%Y-%m-%d %H:%M:%S' -d "@timestamp"
andranikasl
fonte
Ao contrário: date -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna 31/03
3

Eu escrevi um script que faz isso sozinho:

#!/bin/bash
LANG=C
if [ -z "$1" ]; then
    if [  "$(tty)" = "not a tty" ]; then
            p=`cat`;
    else
            echo "No timestamp given."
            exit
    fi
else
    p=$1
fi
echo $p | gawk '{ print strftime("%c", $0); }'
Chiborg
fonte
1
Suas tags de pergunta incluem "bash", mas seu shebang diz "sh".
Pausado até novo aviso.
3

Nesta resposta, copio a resposta de Dennis Williamson e modifico-a levemente para permitir um grande aumento de velocidade ao canalizar uma coluna de muitos registros de data e hora para o script. Por exemplo, o envio de 1000 registros de data e hora para o script original com xargs -n1 na minha máquina levou 6.929s em vez de 0.027s com esta versão modificada:

#!/bin/bash
LANG=C
if [[ -z "$1" ]]
then
    if [[ -p /dev/stdin ]]    # input from a pipe
    then
        cat - | gawk '{ print strftime("%c", $1); }'
    else
        echo "No timestamp given." >&2
        exit
    fi
else
    date -d @$1 +%c
fi
webb
fonte
2

algum exemplo:

$ data
Ter 22 de março 16:47:06 CST 2016

$ date -d "Ter 22 de março às 16:47:06 CST 2016" "+% s"
1458636426

$ data +% s
1458636453

$ data -d @ 1458636426
Ter 22 de março 16:47:06 CST 2016

$ date --date = '@ 1458636426'
Ter 22 de março 16:47:06 CST 2016


kai
fonte
2

Eu uso este liner de plataforma cruzada:

date -d @1267619929 2>/dev/null || date -r 1267619929

Ele deve funcionar no macOS e nas versões posteriores de distribuições comuns do Linux.

Blago
fonte
0

Embora não seja puro bash, o script a seguir converterá carimbos de data e hora de comprimento 13 em uma string para a data equivalente no fuso horário local usando perl

timestamp_to_date.sh

#!/usr/bin/env bash
IT=$(cat /dev/stdin)
re='(.*)([0-9]{13})(.*)'
while [[ $IT =~ $re ]]; do
  TIMESTAMP=${BASH_REMATCH[2]}
  AS_DATE=$(echo "$TIMESTAMP" | perl -pe 's/([\d]{10})([\d]{3})/localtime $1/eg;')
  IT="${IT/$TIMESTAMP/$AS_DATE}"    
done
echo "$IT"

entrada

{"timestamp":"1573121629939","level":"DEBUG","thread":"http-nio-15372-exec-3","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor"}

resultado

$ cat input | timestamp_to_date.sh

{"timestamp":"Thu Nov  7 06:13:49 2019","level":"DEBUG","thread":"http-nio-15372-exec-3","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor"}
Brad Parks
fonte
-8

Em PHP

$unix_time = 1256571985;

echo date("Y-m-d H:i:s",$unix_time)
Lucas
fonte
5
Legal, mas eu só queria usar o bash.
precisa saber é o seguinte