Làm thế nào để chuyển đổi dấu thời gian thành ngày ở Bash?


270

Tôi cần một lệnh shell hoặc script chuyển đổi dấu thời gian Unix thành ngày. Đầu vào có thể đến từ tham số đầu tiên hoặc từ stdin, cho phép các kiểu sử dụng sau:

ts2date 1267619929

echo 1267619929 | ts2date

Cả hai lệnh sẽ xuất ra "Thứ ba 3 13:38:49 2010".

Câu trả lời:


531

Trên các phiên bản sau của các bản phân phối Linux phổ biến, bạn có thể sử dụng:

date -d @1267619929

5
Một lớp lót:date -d @$(date -u +%s)
Mike Atlas

26
Để làm gì @? Tôi không thấy điều đó trong trang GNU GNU.
Đánh dấu E. Haase

13
@mehaase - trang man lưu ý rằng chuỗi ngày quá phức tạp để được ghi lại trong trang, vì vậy nó được mô tả trong thông tin: thông tin '(coreutils) ngày gọi'
MByD

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

2
info 'Date input formats' giúp bạn đi thẳng đến datenút thông tin định dạng, với trích dẫn thích hợp của Robert Grudin, và sau đó là một menu các công cụ định dạng.
chước

165
date -r <number>

hoạt động với tôi trên Mac OS X.


5
Có, nhưng nó không xử lý các phân số của một giây.
mgold

1
Và thật khó hiểu vì nó không hoạt động theo cách đó trên hầu hết các hệ thống linux, bởi vì: freddy @ hades ~% date --help | grep - -r -r, --reference = FILE hiển thị thời gian sửa đổi cuối cùng của FILE
frank42

1
Mặc dù các ý kiến ​​về câu trả lời này là đúng, nhưng đây không phải là lỗi của rafa và chúng không làm giảm câu trả lời của anh ấy.
chước

29

Phiên bản này tương tự như câu trả lời của chiborg , nhưng nó loại bỏ sự cần thiết của bên ngoài ttycat. Nó sử dụng date, nhưng có thể dễ dàng sử dụng gawk. Bạn có thể thay đổi shebang và thay thế dấu ngoặc vuông bằng một dấu ngoặc đơn và điều này cũng sẽ chạy trong 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: câu trả lời rất đầy đủ và tôi nghĩ ngày nhanh hơn gawk.
Bruno Brant

@Bruno, làm sao bạn biết ngày nhanh hơn gawk.?
ghostdog74

3
@Bruno, @ ghostdog74: Trên hệ thống của tôi, gawknhanh hơn 15% so với vòng lặp datethời gian forchỉ bao gồm gawk 'BEGIN { print strftime("%c", 1256571985); }'hoặc date -d '@1256571985' +%ccó đầu ra được chuyển hướng đến /dev/null.
Tạm dừng cho đến khi có thông báo mới.

1
ngày nhanh hơn một chút (5%) so với gawk đối với tôi (mac osx 10.9.2, ngày 8.23, gawk 4.1.1), nhưng lợi thế thực sự của (g) awk là chấp nhận một ống của một cột có nhiều dấu thời gian (xem câu trả lời của tôi dưới đây), làm cho kịch bản, ví dụ 250x nhanh nhất cho 1000 dấu thời gian.
webb

3
Lưu ý rằng câu trả lời của tôi đáp ứng các yêu cầu của OP như đã nêu trong câu hỏi, nhưng câu trả lời hiện được chấp nhận thì không.
Tạm dừng cho đến khi có thông báo mới.

17

Bạn có thể sử dụng ngày GNU, ví dụ,

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

hoặc là

$ date -ud @1267619929

10

Bạn có thể sử dụng tập lệnh awk đơn giản này:

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

Sử dụng mẫu:

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

Điều này không phù hợp với cách sử dụng đầu tiên - đôi khi tôi không muốn lặp lại TS và sử dụng tham số thay thế.
chiborg

Trên một số phiên bản busybox cũ, date -s @không hoạt động, và awkvẫn còn! Một ví dụ không có stdin cũng sẽ hữu ích.
Victor Sergienko

8

Kể từ Bash 4.2 bạn có thể sử dụng printf%(datefmt)Tđịnh dạng:

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

Điều đó thật tuyệt, bởi vì nó là một vỏ dựng sẵn. Định dạng cho datefmt là một chuỗi được chấp nhận bởi strftime(3)(xem man 3 strftime). Đây %clà:

%c Đại diện ngày và thời gian ưa thích cho miền địa phương hiện tại.


Bây giờ nếu bạn muốn một tập lệnh chấp nhận một đối số và, nếu không được cung cấp, đọc stdin, bạn có thể tiến hành như sau:

#!/bin/bash

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

6

Tôi sử dụng điều này khi chuyển đổi tệp nhật ký hoặc theo dõi chúng:

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

chính xác những gì tôi đang tìm kiếm, có thể rút ngắn thànhawk '{ printf strftime("%c: ", $1); $1 = ""; print $0; }'
ChrisWue

5

Trong OSX hoặc BSD, có một -rcờ tương đương có dấu thời gian unix. Đây là một ví dụ chạy ngày bốn lần: một lần cho ngày đầu tiên, để hiển thị nó là gì; một cho việc chuyển đổi thành dấu thời gian unix với %s, và cuối cùng, một trong đó, với -r, chuyển đổi những gì %scung cấp trở lại thành một chuỗi.

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

Ít nhất, dường như làm việc trên máy của tôi.

$ 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

Nếu bạn đã có giá trị dấu thời gian và bạn chỉ cần tìm ngày tương đương, trong OS X, bạn chỉ cần nhập giá trị này vào dòng lệnh: date -r 1509453417
Noel Whitemore

1
Đúng. Nếu bạn nhìn vào câu trả lời của tôi, tôi thực sự đang chứng minh điều đó.
Daniel Farrell

5

Bạn có thể nhận được định dạng ngày từ dấu thời gian như thế này

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

Cách khác: ngày -ud "@ 1585667718" + '% Y-% m-% d% H:% M:% S'
AndiAna

3

Tôi đã viết một kịch bản tự làm điều này:

#!/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
Thẻ câu hỏi của bạn bao gồm "bash", nhưng shebang của bạn nói "sh".
Tạm dừng cho đến khi có thông báo mới.

3

Trong câu trả lời này, tôi sao chép câu trả lời của Dennis Williamson và sửa đổi nó một chút để cho phép tăng tốc độ rất lớn khi đưa một cột có nhiều dấu thời gian vào kịch bản. Ví dụ: chuyển 1000 dấu thời gian sang tập lệnh gốc với xargs -n1 trên máy của tôi mất 6,929 so với 0,027 giây với phiên bản sửa đổi này:

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

một số ví dụ:

$ ngày
Thứ ba ngày 22 tháng 3 16:47:06 CST 2016

$ ngày -d "Thứ ba ngày 22 tháng 3 16:47:06 CST 2016" "+% s"
1458636426

$ ngày +% s
1458636453

$ ngày -d @ 1458636426
Thứ ba ngày 22 tháng 3 16:47:06 CST 2016

$ ngày - ngày = '@ 1458636426'
Thứ ba ngày 22 tháng 3 16:47:06 CST 2016



2

Tôi sử dụng một lớp lót đa nền tảng này:

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

Nó nên hoạt động trong cả macOS và các phiên bản phân phối Linux phổ biến sau này.


0

Mặc dù không phải là bash thuần túy, tập lệnh sau sẽ chuyển đổi dấu thời gian có độ dài 13 trong chuỗi thành ngày tương đương của chúng trong múi giờ địa phương của bạn bằng cách sử dụng 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"

đầu vào

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

đầu ra

$ 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

Trong PHP

$unix_time = 1256571985;

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

5
Đẹp, nhưng tôi chỉ muốn sử dụng bash.
chiborg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.