¿Cómo convertir marcas de tiempo a fechas en Bash?


270

Necesito un comando de shell o script que convierta una marca de tiempo de Unix en una fecha. La entrada puede provenir del primer parámetro o de stdin, lo que permite los siguientes patrones de uso:

ts2date 1267619929

y

echo 1267619929 | ts2date

Ambos comandos deberían mostrar "Mié Mar 3 13:38:49 2010".

Respuestas:


532

En versiones posteriores de distribuciones de Linux comunes, puede usar:

date -d @1267619929

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

26
¿Para qué sirve @? No veo eso en la página de manual de GNU en absoluto.
Mark E. Haase

13
@mehaase: la página de manual señala que la cadena de fecha es demasiado compleja para documentarse en la página de manual, por lo que se describe en info: info '(invocación de fecha de coreutils)'
MByD

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

2
info 'Date input formats' lo lleva directamente al datenodo de información de formato, con la cita pertinente de Robert Grudin, y luego a un menú de especificadores de formato.
mike

165
date -r <number>

funciona para mí en Mac OS X.


55
Sí, pero no maneja fracciones de segundo.
mgold

1
Y es confuso porque no funciona de esa manera en la mayoría de los sistemas Linux, porque: freddy @ hades ~% date --help | grep - -r -r, --reference = FILE muestra la última hora de modificación de FILE
frank42

1
Si bien los comentarios sobre esta respuesta son ciertos, no son culpa de Rafa y no disminuyen su respuesta.
mike

29

Esta versión es similar a la respuesta de chiborg , pero elimina la necesidad de lo externo ttyy cat. Utiliza date, pero podría usarlo con la misma facilidad gawk. Puede cambiar el shebang y reemplazar los corchetes dobles por uno solo y esto también se ejecutará 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: respuesta muy completa y creo que la fecha es más rápida que gawk.
Bruno Brant

@Bruno, ¿cómo sabes que la fecha es más rápida que gawk?
ghostdog74

3
@Bruno, @ ghostdog74: en mi sistema, gawkes (aproximadamente) un 15% más rápido que dateen un forbucle temporizado que consiste solo gawk 'BEGIN { print strftime("%c", 1256571985); }'o date -d '@1256571985' +%ccon salida redirigida a /dev/null.
Pausado hasta nuevo aviso.

1
la fecha es marginalmente (5%) más rápida que gawk para mí (mac osx 10.9.2, fecha 8.23, gawk 4.1.1), pero la verdadera ventaja de (g) awk es aceptar una tubería de una columna de muchas marcas de tiempo (ver mi respuesta a continuación), lo que hace que el script sea, por ejemplo, 250 veces más rápido para 1000 marcas de tiempo.
webb

3
Tenga en cuenta que mi respuesta cumple con los requisitos del OP como se indica en la pregunta, pero la respuesta ahora aceptada no.
Pausado hasta nuevo aviso.

17

Puede usar la fecha GNU, por ejemplo,

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

o

$ date -ud @1267619929

10

Puedes usar este simple script awk:

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

Uso de la muestra:

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

Esto no se ajusta al primer uso; a veces no quiero hacer eco del TS y usar un parámetro en su lugar.
chiborg

En algunas versiones antiguas de busybox, date -s @no funciona, ¡y awktodavía lo hace! Un ejemplo sin un stdin también sería útil.
Victor Sergienko

8

Desde Bash 4.2 puedes usar printfel %(datefmt)Tformato de:

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

Eso es bueno, porque es una concha incorporada. El formato para datefmt es una cadena aceptada por strftime(3)(ver man 3 strftime). Aqui %cesta:

%c La representación de fecha y hora preferida para el entorno local actual.


Ahora, si desea un script que acepte un argumento y, si no se proporciona ninguno, lea stdin, puede proceder como:

#!/bin/bash

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

6

Lo uso al convertir archivos de registro o monitorearlos:

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

exactamente lo que estaba buscando, se puede acortar aawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue

5

En OSX o BSD, hay una -rbandera equivalente que aparentemente toma una marca de tiempo de Unix. Aquí hay un ejemplo que ejecuta la fecha cuatro veces: una vez para la primera fecha, para mostrar lo que es; uno para la conversión a marca de tiempo de Unix con %s, y finalmente, uno que, con -r, convierte lo que %sproporciona de nuevo a una cadena.

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

Al menos, parece funcionar en mi 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

Si ya tiene un valor de marca de tiempo y solo necesita encontrar la fecha equivalente, en OS X puede escribir esto en la línea de comando: fecha -r 1509453417
Noel Whitemore

1
Es verdad. Si miras mi respuesta, en realidad lo estoy demostrando.
Daniel Farrell

5

Puede obtener la fecha formateada de la marca de tiempo como esta

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

Al revés: date -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna

3

He escrito un guión que hace esto yo mismo:

#!/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
Sus etiquetas de preguntas incluyen "bash", pero su shebang dice "sh".
Pausado hasta nuevo aviso.

3

En esta respuesta, copio la respuesta de Dennis Williamson y la modifico ligeramente para permitir un gran aumento de velocidad al canalizar una columna de muchas marcas de tiempo al guión. Por ejemplo, conectar 1000 marcas de tiempo al script original con xargs -n1 en mi máquina tomó 6.929s en lugar de 0.027s con esta versión 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

2

algún ejemplo:

$ fecha
Martes 22 de marzo 16:47:06 CST 2016

$ fecha -d "Mar 22 de marzo 16:47:06 CST 2016" "+% s"
1458636426

$ fecha +% s
1458636453

$ fecha -d @ 1458636426
Martes 22 de marzo 16:47:06 CST 2016

$ date --date = '@ 1458636426'
Martes 22 de marzo 16:47:06 CST 2016



2

Yo uso este one-liner multiplataforma:

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

Debería funcionar tanto en macOS como en versiones posteriores de distribuciones comunes de Linux.


0

Si bien no es puro bash, el siguiente script convertirá las marcas de tiempo de longitud 13 en una cadena a su fecha equivalente en su zona horaria 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"}

salida

$ 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

En PHP

$unix_time = 1256571985;

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

55
Bien, pero solo quería usar bash.
chiborg
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.