开发者

Convert Unix timestamp to a date string

Is there a quick, one-liner way to convert a Unix timestamp to a date from the Unix command line?

date might work, except it's rather awkward to specify each element (month, day, year, hour, etc.), and I can't figure out how to get it to work properly. It seems like there might be开发者_开发问答 an easier way — am I missing something?


With date from GNU coreutils you can do:

date -d "@$TIMESTAMP"
# date -d @0
Wed Dec 31 19:00:00 EST 1969

(From: BASH: Convert Unix Timestamp to a Date)

On OS X, use date -r.

date -r "$TIMESTAMP"

Alternatively, use strftime(). It's not available directly from the shell, but you can access it via gawk. The %c specifier displays the timestamp in a locale-dependent manner.

echo "$TIMESTAMP" | gawk '{print strftime("%c", $0)}'
# echo 0 | gawk '{print strftime("%c", $0)}'
Wed 31 Dec 1969 07:00:00 PM EST


date -d @1278999698 +'%Y-%m-%d %H:%M:%S' Where the number behind @ is the number in seconds


This solution works with versions of date which do not support date -d @. It does not require AWK or other commands. A Unix timestamp is the number of seconds since Jan 1, 1970, UTC so it is important to specify UTC.

date -d '1970-01-01 1357004952 sec UTC'
Mon Dec 31 17:49:12 PST 2012

If you are on a Mac, then use:

date -r 1357004952

Command for getting epoch:

date +%s
1357004952

Credit goes to Anton: BASH: Convert Unix Timestamp to a Date


As @TomMcKenzie says in a comment to another answer, date -r 123456789 is arguably a more common (i.e. more widely implemented) simple solution for times given as seconds since the Unix Epoch, but unfortunately there's no universal guaranteed portable solution.

The -d option on many types of systems means something entirely different than GNU Date's --date extension. Sadly GNU Date doesn't interpret -r the same as these other implementations. So unfortunately you have to know which version of date you're using, and many older Unix date commands don't support either option.

Even worse, POSIX date recognizes neither -d nor -r and provides no standard way in any command at all (that I know of) to format a Unix time from the command line (since POSIX Awk also lacks strftime()). (You can't use touch -t and ls because the former does not accept a time given as seconds since the Unix Epoch.)

Note though The One True Awk available direct from Brian Kernighan does now have the strftime() function built-in as well as a systime() function to return the current time in seconds since the Unix Epoch), so perhaps the Awk solution is the most portable.


If you find the notation awkward, maybe the -R-option does help. It outpouts the date in RFC 2822 format. So you won't need all those identifiers: date -d @1278999698 -R. Another possibility is to output the date in seconds in your locale: date -d @1278999698 +%c. Should be easy to remember. :-)


Slight correction to dabest1's answer above. Specify the timezone as UTC, not GMT:

$ date -d '1970-01-01 1416275583 sec GMT'
Tue Nov 18 00:53:03 GMT 2014
$ date -d '1970-01-01 1416275583 sec UTC'
Tue Nov 18 01:53:03 GMT 2014

The second one is correct. I think the reason is that in the UK, daylight saving was in force continually from 1968 to 1971.


Other examples here are difficult to remember. At its simplest:

date -r 1305712800


The standard Perl solution is:

echo $TIMESTAMP | perl -nE 'say scalar gmtime $_'

(or localtime, if preferred)


awk 'BEGIN { print strftime("%c", 1271603087); }'


Put the following in your ~/.bashrc :

function unixts() { date -d "@$1"; }

Example usage:

$ unixts 1551276383

Wed Feb 27 14:06:23 GMT 2019


Python:

python -c "from datetime import datetime; print(datetime.fromtimestamp($TIMESTAMP))"


3 remarks:

.1 about bash

As this question is tagged bash and no answer here address printf bashism:

Syntax: printf '%(fmt)T' $UNIXEPOCH

Under bash, from V4.2, (Feb 2011), The printf builtin has a %(fmt)T specifier, which allows time values to use strftime-like formatting.

TZ=UTC LANG=C printf '%(%A %d %b %Y, %T %Z)T\n' 12345678
Saturday 23 May 1970, 21:21:18 UTC

Used without argument or with -1 as argument, this will print current time:

printf '%(%b %d, %T)T\n' 
Aug 03, 08:42:28

As printf repeat format sequenc for as many argument present in command line:

$ TZ=UTC LANG=C printf '%(%A %d %b %Y, %T %Z)T\n' -1 123456789 $EPOCHSECONDS
Sunday 20 Nov 2022, 13:04:42 UTC
Thursday 29 Nov 1973, 21:33:09 UTC
Sunday 20 Nov 2022, 13:04:42 UTC

Without argument and without fmt string, printf '%()T' will print current time:

printf '%()T\n'
12:34:56

echo $(( $(TZ=UTC printf "%()T" | sed 's/:/* 3600 +/;s/:/* 60 +/') -
         $(printf "%(%s)T") % 86400 ))
0

.2 The $EPOCHSECONDS and $EPOCHREALTIME integer variables

From V5.0, bash's environment present two integer variables: $EPOCHSECONDS which expands to the time in seconds since the Unix epoch and $EPOCHREALTIME which expands to the time in seconds since the Unix epoch with microsecond granularity..

myvar1=$(LANG=C date -d 'now -1 day' +%c)
LANG=C printf -v myvar2 '%(%c)T' $(( EPOCHSECONDS - 86400 ))
[[ $myvar1 == "$myvar2" ]] || echo "Something's wrong: '$myvar1' != '$myvar2'!"

Except in a very small time laps, where time rounded to second increment by one second between setting $myvar1 and $myvar2, this code won't produce any output as $myvar1 should contain exactly same string than $myvar2.

declare -p myvar{1,2}
declare -- myvar1="Tue Aug  2 11:11:35 2022"
declare -- myvar2="Tue Aug  2 11:11:35 2022"

As printf is a builtin, there is no fork for assigning string variable from UNIXTIME conversion.

The only difference would be resource footprint, then execution time.

Further informations and recommendations about $EPOCHREALTIME, see How to print current time in microseconds using bash builtin

.3 About GNU date

option -f for many entries

Using GNU date, if you plan to format a big bunch of unixtimestamp, you could use date command as a filter.

First you have to add a At (@) before each timestamp, then date -f could process each input lines in one operation:

sed 's/^/@/' < inputfile |
    date -f - +'%A %d %b %Y, %T %Z'

Sample:

seq 123456789 $(((EPOCHSECONDS-123456789)/4)) $EPOCHSECONDS |
    sed 's/^/@/' |
    LANG=C TZ=GMT date -f - +'%A %d %b %Y, %T %Z'

Should produce something like:

Thursday 29 Nov 1973, 21:33:09 GMT
Thursday 30 Jan 1986, 11:53:49 GMT
Thursday 02 Apr 1998, 02:14:29 GMT
Wednesday 02 Jun 2010, 16:35:09 GMT
Wednesday 03 Aug 2022, 06:55:49 GMT

.4 Converting streamed logfile

Sample using tail -f squid/access.log, from a remote server.

squid logs look like:

1659526597.212 240128 192.168.0.184 TCP_TUNNEL/200 3383 CONNECT safebrowsing.googleapis.com:443 - HIER_DIRECT/172.217.168.74 -
1659526614.078    753 192.168.0.91 TCP_TUNNEL/200 3800 CONNECT shavar.services.mozilla.com:443 - HIER_DIRECT/44.236.110.253 -

To be able to remotely follow some squid proxy I could use this:

exec {fd}<> <(:) # This will open unnamed fifo.

Then

ssh root@proxyserver tail -f /var/log/squid/access.log |
    tee >(
        exec sed -ue 's/^\([0-9]\+\)\..*/@\1/'|
            stdbuf -i0 -o0 date -f - +%c >/dev/fd/$fd
     ) |
    sed -ue 's/^[0-9]\+\././'|
        paste -d '' /dev/fd/$fd -

This will output without buffering, something like this:

Wed Aug  3 13:36:37 2022.212 240128 192.168.0.184 TCP_TUNNEL/200 3383 CONNECT safebrowsing.googleapis.com:443 - HIER_DIRECT/172.217.168.74 -
Wed Aug  3 13:36:54 2022.078    753 192.168.0.91 TCP_TUNNEL/200 3800 CONNECT shavar.services.mozilla.com:443 - HIER_DIRECT/44.236.110.253 -

Could be stopped by Ctrl+C, then re-run many time, until you close $fd unnamed fifo by:

exec {fd}<&-
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜