167

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?

ib.
  • 27,830
  • 11
  • 80
  • 100
chimeracoder
  • 20,648
  • 21
  • 60
  • 60
  • 3
    possible duplicate of [How to convert timestamps to dates in bash?](http://stackoverflow.com/questions/2371248/how-to-convert-timestamps-to-dates-in-bash) – user May 01 '14 at 03:28

12 Answers12

242

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
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 6
    Make sure to eliminate the milliseconds from the timestamp (that is only 10 digits instead of 13), otherwise you'll get invalid results (this is true for macOS' date). – emerino Jun 04 '18 at 17:29
  • I thought this was not working, until I realised I had a timestamp in millis. Chop off the last 3 digits, and you get the accurate time – Stewart Aug 10 '18 at 06:33
  • The "Convert Unix Timestamp" link is broken. Archived version: https://web.archive.org/web/20200930143943/https://www.antonolsen.com/2006/04/06/bash-convert-unix-timestamp-to-a-date/ . I would edit the post with the new URL, but the edit queue is full right now. – AJM Aug 17 '22 at 10:58
81

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

Derek Mahar
  • 27,608
  • 43
  • 124
  • 174
qbi
  • 2,104
  • 1
  • 23
  • 35
29

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 in the input.

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

dabest1
  • 2,347
  • 6
  • 25
  • 25
  • 2
    The URL is out-of-date - use this archived version instead: https://web.archive.org/web/20200930143943/https://www.antonolsen.com/2006/04/06/bash-convert-unix-timestamp-to-a-date/ – AJM Aug 17 '22 at 11:00
  • Specifying `UTC` flag is a lot simpler than that :::: `gnu-date -u -d'@1357004952'` ; `bsd-date -u -r 1357004952` :: `Tue Jan 1 01:49:12 UTC 2013 Tue Jan 1 01:49:12 UTC 2013` – RARE Kpop Manifesto May 16 '23 at 19:27
  • You may have misread the answer. My answer is for cases when you do not have support for `date -d @` and when you want to display the output in your local time zone. – dabest1 May 19 '23 at 04:20
11

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.

Greg A. Woods
  • 2,663
  • 29
  • 26
5

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.

Tony Mountifield
  • 99
  • 1
  • 3
  • 6
  • Well done for spotting *that* unexpected corner case! – AJM Aug 17 '22 at 11:05
  • Using Git Bash on Windows 10, both the GMT and UTC versions of the above command output the same thing - `Tue Nov 18 01:53:03 GMTST 2014`. – AJM Aug 17 '22 at 14:18
  • Is this definitely Bash you're using? Could this have been the Korn shell that this idiosyncratic output came from? – AJM Aug 17 '22 at 15:44
4

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. :-)

qbi
  • 2,104
  • 1
  • 23
  • 35
2

The standard Perl solution is:

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

(or localtime, if preferred)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
William Pursell
  • 204,365
  • 48
  • 270
  • 300
2

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

date -r 1305712800
denmojo
  • 223
  • 2
  • 8
1
awk 'BEGIN { print strftime("%c", 1271603087); }'
Sjoerd
  • 74,049
  • 16
  • 131
  • 175
1

Put the following in your ~/.bashrc :

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

Example usage:

$ unixts 1551276383

Wed Feb 27 14:06:23 GMT 2019
Dangelov
  • 701
  • 6
  • 14
0

Python:

python -c "from datetime import datetime; print(datetime.fromtimestamp($TIMESTAMP))"
Itachi
  • 5,777
  • 2
  • 37
  • 69
0

3 remarks:

.1 about

As this question is tagged 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

This could be titled

Convert streamed Unix timestamp to date strings in real time.

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}<&-
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137