Come convertire i timestamp in date in Bash?


270

Ho bisogno di un comando shell o di uno script che converta un timestamp Unix in una data. L'input può provenire dal primo parametro o dallo stdin, consentendo i seguenti schemi di utilizzo:

ts2date 1267619929

e

echo 1267619929 | ts2date

Entrambi i comandi dovrebbero visualizzare "Mer 3 marzo 13:38:49 2010".

Risposte:


532

Nelle versioni successive delle comuni distribuzioni Linux è possibile utilizzare:

date -d @1267619929

5
One-liner:date -d @$(date -u +%s)
Mike Atlas

26
A cosa serve @? Non lo vedo affatto nella pagina man di GNU.
Mark E. Haase,

13
@mehaase - la pagina man nota che la stringa della data è troppo complessa per essere documentata nella manpage, quindi è descritta in info: info '(coreutils) invocazione della data'
MByD

10
brew install coreutils; gdate -d @1267619929
Mark Fox,

2
info 'Date input formats' ti porta direttamente al datenodo informativo di formattazione, con la pertinente citazione di Robert Grudin, e quindi un menu di identificatori di formato.
mike

165
date -r <number>

funziona per me su Mac OS X.


5
Sì, ma non gestisce le frazioni di secondo.
mgold

1
Ed è confuso perché non funziona in questo modo sulla maggior parte dei sistemi Linux, perché: freddy @ hades ~% date --help | grep - -r -r, --reference = FILE visualizza l'ora dell'ultima modifica di FILE
frank42

1
mentre i commenti su questa risposta sono veri, questi non sono colpa di Rafa e non diminuiscono la sua risposta.
mike

29

Questa versione è simile alla risposta di Chiborg , ma elimina la necessità di esterni ttye cat. Usa date, ma potrebbe altrettanto facilmente usare gawk. Puoi cambiare lo shebang e sostituire le doppie parentesi quadre con singole e anche questo funzionerà 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

+1: risposta molto completa e penso che la data sia più veloce di gawk.
Bruno Brant

@Bruno, come fai a sapere che la data è più veloce di gawk.?
ghostdog74

3
@Bruno, @ ghostdog74: Sul mio sistema, gawkè (molto più o meno) del 15% più veloce rispetto datea un forloop temporizzato costituito solo da gawk 'BEGIN { print strftime("%c", 1256571985); }'o date -d '@1256571985' +%ccon output reindirizzato a /dev/null.
In pausa fino a nuovo avviso.

1
la data è marginalmente (5%) più veloce di gawk per me (mac osx 10.9.2, data 8.23, gawk 4.1.1), ma il vero vantaggio di (g) awk è accettare una pipe di una colonna di molti timestamp (vedi la mia risposta di seguito), che rende lo script ad esempio 250x più veloce per 1000 timestamp.
webb,

3
Nota che la mia risposta soddisfa i requisiti del PO come indicato nella domanda, ma la risposta ora accettata no.
In pausa fino a nuovo avviso.

17

È possibile utilizzare la data GNU, ad esempio,

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

o

$ date -ud @1267619929

10

Puoi usare questo semplice script awk:

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

Esempio di utilizzo:

$ echo '1098181096' | ./a.awk 
Tue 19 Oct 2004 03:18:16 AM PDT
$

Questo non si adatta al primo utilizzo - a volte non voglio fare eco al TS e utilizzare invece un parametro.
chiborg,

Su alcune vecchie versioni di busybox, date -s @non funziona e awkfunziona ancora! Sarebbe utile anche un esempio senza stdin.
Victor Sergienko,

8

Da Bash 4.2 puoi usare printfil %(datefmt)Tformato:

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

È carino, perché è una shell integrata. Il formato per datefmt è una stringa accettata da strftime(3)(vedi man 3 strftime). Ecco qui %c:

%c La rappresentazione della data e dell'ora preferite per la locale corrente.


Ora se vuoi uno script che accetta un argomento e, se non ne viene fornito uno, legge stdin, puoi procedere come:

#!/bin/bash

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

6

Lo uso quando converto i file di registro o li controllo:

tail -f <log file> | gawk \
'{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }'

esattamente quello che stavo cercando, può essere abbreviato inawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue,

5

In OSX, o BSD, c'è un -rflag equivalente che apparentemente prende un timestamp unix. Ecco un esempio che esegue la data quattro volte: una volta per la prima data, per mostrare di cosa si tratta; uno per la conversione in unix timestamp con %s, e infine, uno che, con -r, converte ciò che %sfornisce in una stringa.

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

Almeno, sembra funzionare sulla mia macchina.

$ 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

Se hai già un valore di data e ora e devi solo trovare la data equivalente, in OS X puoi semplicemente digitarlo nella riga di comando: data -r 1509453417
Noel Whitemore

1
È vero. Se guardi la mia risposta, lo sto dimostrando.
Daniel Farrell,

5

È possibile ottenere la data formattata dal timestamp in questo modo

date +'%Y-%m-%d %H:%M:%S' -d "@timestamp"

In alternativa: data -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna

3

Ho scritto una sceneggiatura che lo fa da solo:

#!/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); }'

1
I tag delle domande includono "bash", ma il tuo shebang dice "sh".
In pausa fino a nuovo avviso.

3

In questa risposta copio la risposta di Dennis Williamson e la modifico leggermente per consentire un notevole aumento della velocità quando si esegue il piping di una colonna di molti timestamp sullo script. Ad esempio, il piping di 1000 timestamp allo script originale con xargs -n1 sulla mia macchina ha richiesto 6.929s rispetto a 0.027s con questa versione modificata:

#!/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

2

qualche esempio:

$ data
Mar 22 Mar 16:47:06 CST 2016

$ date -d "mar 22 16:47:06 CST 2016" "+% s"
1458636426

$ data +% s
1458636453

$ date -d @ 1458636426
Mar 22 Mar 16:47:06 CST 2016

$ date --data = '@ 1458636426'
Mar 22 Mar 16:47:06 CST 2016



2

Uso questo one-liner multipiattaforma:

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

Dovrebbe funzionare sia in macOS che nelle versioni successive delle comuni distribuzioni Linux.


0

Sebbene non sia bash puro, il seguente script convertirà i timestamp di lunghezza 13 in una stringa nella loro data equivalente nel tuo fuso orario locale 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"

ingresso

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

produzione

$ 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"}

-8

In PHP

$unix_time = 1256571985;

echo date("Y-m-d H:i:s",$unix_time)

5
Bello, ma volevo solo usare bash.
Chiborg,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.