Как конвертировать метки времени в даты в Bash?

270

Мне нужна команда оболочки или сценарий, который преобразует метку времени Unix в дату. Входные данные могут поступать либо из первого параметра, либо из stdin, что позволяет использовать следующие шаблоны использования:

ts2date 1267619929

и

echo 1267619929 | ts2date

Обе команды должны вывести «Ср 3 марта 13:38:49 2010».

chiborg
источник

Ответы:

532

В более поздних версиях распространенных дистрибутивов Linux вы можете использовать:

date -d @1267619929
a'r
источник
5
One-liner:date -d @$(date -u +%s)
Майк Атлас
26
Для чего @? Я не вижу этого на странице руководства GNU вообще.
Марк Э. Хаазе
13
@mehaase - страница руководства отмечает, что строка даты слишком сложна, чтобы ее можно было документировать на странице руководства, поэтому она описана в info: info '(coreutils) date invocation'
MByD
10
brew install coreutils; gdate -d @1267619929
Марк Фокс
2
info 'Date input formats' возвращает вас прямо к dateинформационному узлу форматирования, с соответствующей цитатой Роберта Грудина, а затем с меню спецификаторов формата.
Майк
165
date -r <number>

у меня работает на Mac OS X.

rafaelzlisboa
источник
5
Да, но он не обрабатывает доли секунды.
mgold
1
И это сбивает с толку, потому что это не работает таким образом на большинстве систем Linux, потому что: freddy @ hades ~% date --help | grep - -r -r, --reference = FILE - отображать время последнего изменения FILE
frank42
1
Хотя комментарии к этому ответу верны, это не вина Рафы, и они не умаляют его ответ.
Майк
29

Эта версия похожа на ответ Чиборга , но устраняет необходимость внешнего ttyи cat. Он использует date, но может так же легко использовать gawk. Вы можете изменить shebang и заменить двойные квадратные скобки на одинарные, и это также будет работать 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: очень полный ответ, и я думаю, что дата быстрее, чем gawk.
Бруно Брант
@ Бруно, откуда ты знаешь, что дата быстрее, чем поглазеть?
ghostdog74
3
@Bruno, @ ghostdog74: В моей системе gawk(очень приблизительно) на 15% быстрее, чем dateв синхронизированном forцикле, состоящем только из gawk 'BEGIN { print strftime("%c", 1256571985); }'или date -d '@1256571985' +%cс перенаправленным выводом /dev/null.
Приостановлено до дальнейшего уведомления.
1
date немного (на 5%) быстрее, чем gawk для меня (mac osx 10.9.2, date 8.23, gawk 4.1.1), но реальное преимущество (g) awk заключается в том, что он принимает канал из столбца с множеством временных отметок (см. мой ответ ниже), что делает скрипт, например, 250x быстрым для 1000 временных меток.
Уэбб
3
Обратите внимание, что мой ответ соответствует требованиям ОП, как указано в вопросе, но принятый сейчас ответ не соответствует.
Приостановлено до дальнейшего уведомления.
17

Вы можете использовать дату GNU, например,

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

или

$ date -ud @1267619929
ghostdog74
источник
10

Вы можете использовать этот простой скрипт на awk:

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

Пример использования:

$ echo '1098181096' | ./a.awk 
Tue 19 Oct 2004 03:18:16 AM PDT
$
codaddict
источник
Это не подходит для первого использования - иногда я не хочу отображать TS и использовать параметр вместо этого.
Чиборг
На некоторых старых версиях busybox date -s @не работает и awkработает! Пример без stdin тоже будет полезен.
Виктор Сергиенко
8

Поскольку Bash 4.2 вы можете использовать printf«S %(datefmt)Tформат:

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

Это хорошо, потому что это встроенная оболочка. Формат для datefmt - строка, принятая strftime(3)(см. man 3 strftime). Вот %c:

%c Предпочтительное представление даты и времени для текущей локали.


Теперь, если вам нужен скрипт, который принимает аргумент и, если он не предоставлен, читает stdin, вы можете выполнить следующее:

#!/bin/bash

if (($#)); then
    printf '%(%c)T\n' "$@"
else
    while read -r line; do
        printf '%(%c)T\n' "$line"
    done
fi
gniourf_gniourf
источник
6

Я использую это при преобразовании файлов журнала или мониторинга их:

tail -f <log file> | gawk \
'{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }'
user3544224
источник
именно то, что я искал, может быть сокращено доawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue
5

В OSX, или BSD, есть эквивалентный -rфлаг, который, очевидно, использует метку времени Unix. Вот пример, который запускает дату четыре раза: один раз для первой даты, чтобы показать, что это такое; один для преобразования в unix timestamp с %s, и, наконец, один, который с помощью -r, преобразует то, что %sобеспечивает обратно в строку.

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

По крайней мере, похоже, работает на моей машине.

$ 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
Дэниел Фаррелл
источник
Если у вас уже есть значение метки времени, и вам просто нужно найти эквивалентную дату, в OS X вы можете просто ввести ее в командной строке: date -r 1509453417
Noel
1
Это правда. Если вы посмотрите на мой ответ, я на самом деле демонстрирую это.
Даниэль Фаррелл
5

Вы можете получить отформатированную дату из отметки времени следующим образом

date +'%Y-%m-%d %H:%M:%S' -d "@timestamp"
andranikasl
источник
Другой способ: date -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna
3

Я написал скрипт, который делает это сам:

#!/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
источник
1
Ваши теги вопросов включают в себя "bash", но ваш шебанг говорит "sh".
Приостановлено до дальнейшего уведомления.
3

В этом ответе я копирую ответ Денниса Уильямсона и слегка его изменяю, чтобы значительно увеличить скорость при передаче столбца с множеством временных меток в сценарий. Например, передача 1000 временных меток к исходному сценарию с xargs -n1 на моей машине заняла 6,929 с, а не 0,027 с этой модифицированной версией:

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

некоторый пример:

$ date
Вт мар 22 16:47:06 CST 2016

$ date -d "вт 22 мар. 16:47:06 CST 2016" "+% s"
1458636426

$ date +% s
1458636453

$ date -d @ 1458636426
Вт мар 22 16:47:06 CST 2016

$ date --date = '@ 1458636426'
Вт мар 22 16:47:06 CST 2016


кай
источник
2

Я использую этот кроссплатформенный однострочник:

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

Он должен работать как в macOS, так и в более поздних версиях распространенных дистрибутивов Linux.

Blago
источник
0

Хотя это и не чистый bash, следующий скрипт преобразует метки времени длиной 13 в строке в их эквивалентную дату в вашем местном часовом поясе, используя 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"

вход

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

вывод

$ 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

В PHP

$unix_time = 1256571985;

echo date("Y-m-d H:i:s",$unix_time)
Лукас
источник
5
Хорошо, но я просто хотел использовать bash.
Чиборг