Jak przekonwertować znaczniki czasu na daty w Bash?

270

Potrzebuję polecenia powłoki lub skryptu, który konwertuje uniksowy znacznik czasu na datę. Dane wejściowe mogą pochodzić albo z pierwszego parametru, albo ze standardowego wejścia, umożliwiając następujące wzorce użytkowania:

ts2date 1267619929

i

echo 1267619929 | ts2date

Oba polecenia powinny wypisać „Śr 3 marca 38:38:49 2010”.

Chiborg
źródło

Odpowiedzi:

531

W nowszych wersjach popularnych dystrybucji Linuksa możesz użyć:

date -d @1267619929
a'r
źródło
5
One-liner:date -d @$(date -u +%s)
Mike Atlas,
26
Do czego służy @? Nie widzę tego wcale na stronie podręcznika GNU.
Mark E. Haase
13
@mehaase - strona podręcznika zauważa, że ​​ciąg daty jest zbyt skomplikowany, aby można go było udokumentować na stronie podręcznika, więc jest opisany w info: info '(coreutils) date invocation'
MByD
10
brew install coreutils; gdate -d @1267619929
Mark Fox
2
info 'Date input formats'dateprzeniesie Cię bezpośrednio do węzła informacji o formatowaniu, z odpowiednim cytatem Roberta Grudina, a następnie menu specyfikatorów formatu.
Mike,
165
date -r <number>

działa dla mnie w systemie Mac OS X.

rafaelzlisboa
źródło
5
Tak, ale nie obsługuje ułamków sekundy.
mgold
1
I to jest mylące, ponieważ nie działa w ten sposób na większości systemów Linux, ponieważ: freddy @ hades ~% date --help | grep - -r -r, --reference = PLIK wyświetla czas ostatniej modyfikacji PLIKU
frank42
1
podczas gdy komentarze do tej odpowiedzi są prawdziwe, nie są one winą Rafy i nie umniejszają jego odpowiedzi.
mike
29

Ta wersja jest podobna do odpowiedzi Chiborga , ale eliminuje potrzebę zewnętrznego ttyi cat. Używa date, ale równie łatwo może z niego korzystać gawk. Możesz zmienić shebang i zastąpić podwójne nawiasy kwadratowe pojedynczymi, a to również się pojawi 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
Wstrzymano do odwołania.
źródło
+1: bardzo kompletna odpowiedź i myślę, że data jest szybsza niż gawk.
Bruno Brant
@Bruno, skąd wiesz, że data jest szybsza niż gawk.?
ghostdog74
3
@Bruno, @ ghostdog74: W moim systemie gawkjest (bardzo z grubsza) 15% szybszy niż datew forpętli czasowej składającej się tylko z gawk 'BEGIN { print strftime("%c", 1256571985); }'lub date -d '@1256571985' +%cz przekierowaniem wyjścia /dev/null.
Wstrzymano do odwołania.
1
data jest nieznacznie (5%) szybsza niż gawk dla mnie (Mac OSX 10.9.2, data 8.23, gawk 4.1.1), ale prawdziwą zaletą (g) awk jest zaakceptowanie potoku kolumny wielu znaczników czasu (patrz moja odpowiedź poniżej), co sprawia, że ​​skrypt np. jest 250 razy szybszy na 1000 znaczników czasu.
webb
3
Zauważ, że moja odpowiedź spełnia wymagania PO określone w pytaniu, ale odpowiedź zaakceptowana teraz nie.
Wstrzymano do odwołania.
17

Możesz użyć daty GNU, na przykład

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

lub

$ date -ud @1267619929
ghostdog74
źródło
10

Możesz użyć tego prostego skryptu awk:

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

Przykładowe użycie:

$ echo '1098181096' | ./a.awk 
Tue 19 Oct 2004 03:18:16 AM PDT
$
kodaddict
źródło
To nie pasuje do pierwszego użycia - czasami nie chcę echa TS i zamiast tego używać parametru.
chiborg,
W niektórych starych wersjach busybox date -s @nie działa i awknadal działa! Pomocny byłby też przykład bez standardowego wejścia.
Victor Sergienko
8

Od Bash 4.2 można użyć printf„s %(datefmt)Tformat:

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

To miłe, ponieważ jest to wbudowana powłoka. Format datefmt jest łańcuchem akceptowanym przez strftime(3)(patrz man 3 strftime). Oto %c:

%c Preferowana reprezentacja daty i godziny dla bieżących ustawień regionalnych.


Teraz, jeśli chcesz skrypt, który akceptuje argument, a jeśli nie zostanie podany, czyta standardowe wejście, możesz postępować następująco:

#!/bin/bash

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

Używam tego podczas konwertowania plików dziennika lub monitorowania:

tail -f <log file> | gawk \
'{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }'
użytkownik3544224
źródło
dokładnie tego, czego szukałem, można skrócićawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue
5

W OSX lub BSD istnieje równoważna -rflaga, która najwyraźniej przyjmuje znacznik czasu unix. Oto przykład, który uruchamia datę cztery razy: raz dla pierwszej daty, aby pokazać, co to jest; jeden do konwersji na znacznik czasu unix za pomocą %s, i wreszcie ten, który za pomocą -rkonwertuje to, co %szapewnia z powrotem na ciąg.

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

Wydaje się, że przynajmniej działa na moim komputerze.

$ 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
źródło
Jeśli masz już wartość znacznika czasu i potrzebujesz tylko znaleźć równoważną datę, w OS X możesz po prostu wpisać ją w wierszu polecenia: data -r 1509453417
Noel Whitemore
1
To prawda. Jeśli spojrzysz na moją odpowiedź, faktycznie to demonstruję.
Daniel Farrell
5

Możesz uzyskać sformatowaną datę z datownika w ten sposób

date +'%Y-%m-%d %H:%M:%S' -d "@timestamp"
andranikasl
źródło
Odwrotnie: data -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna
3

Napisałem skrypt, który sam to robi:

#!/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
źródło
1
Twoje tagi pytań zawierają „bash”, ale twój shebang mówi „sh”.
Wstrzymano do odwołania.
3

W tej odpowiedzi kopiuję odpowiedź Dennisa Williamsona i nieznacznie ją modyfikuję, aby umożliwić znaczny wzrost prędkości podczas przesyłania do skryptu kolumny wielu znaczników czasu. Na przykład przesłanie 1000 znaczników czasu do oryginalnego skryptu za pomocą xargs -n1 na moim komputerze zajęło 6,929 s, w przeciwieństwie do 0,027 s w tej zmodyfikowanej wersji:

#!/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
źródło
2

jakiś przykład:

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

$ date -d "Wt 22.03 16:47:06 CST 2016" "+% s"
1458636426

Data $ +% s
1458636453

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

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


kai
źródło
2

Używam tego jednopłytkowego międzyplatformowego:

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

Powinien działać zarówno w systemie macOS, jak i późniejszych wersjach popularnych dystrybucji systemu Linux.

Blago
źródło
0

Chociaż nie jest to czysta bash, poniższy skrypt przekonwertuje znaczniki czasu o długości 13 w ciągu na ich równoważną datę w lokalnej strefie czasowej przy użyciu perla

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"

Wejście

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

wynik

$ 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
źródło
-8

W PHP

$unix_time = 1256571985;

echo date("Y-m-d H:i:s",$unix_time)
Lucas
źródło
5
Fajnie, ale chciałem tylko użyć bash.
chiborg,