Convert Unix timestamp to a date string

Viewed 194530

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?

12 Answers

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))"

Some remarks:

.1 about

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

The printf '%(fmt)T syntax

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

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

.2 About

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 < inputfile 's/^/@/' |
    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

Sample using tail -f squid/access.log

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 6<> <(:) # 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/6
     ) |
    sed -ue 's/^[0-9]\+\././'|
        paste -d '' /dev/fd/6 -

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.

Related