I need a shell command or script that converts a Unix timestamp to a date. The input can come either from the first parameter or from stdin, allowing for the following usage patterns:
ts2date 1267619929 and
echo 1267619929 | ts2date Both commands should output "Wed Mar 3 13:38:49 2010".
17 Answers
On systems with GNU Coreutils >= 5.3.0, e.g. Linux you can use:
date -d @1267619929 6date -r <number> works for me on Mac OS X.
3This version is similar to chiborg's answer, but it eliminates the need for the external tty and cat. It uses date, but could just as easily use gawk. You can change the shebang and replace the double square brackets with single ones and this will also run in 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 6You can use GNU date, for example,
$ sec=1267619929 $ date -d "UTC 1970-01-01 $sec secs" or
$ date -ud @1267619929 You can get formatted date from timestamp like this
date +'%Y-%m-%d %H:%M:%S' -d "@timestamp" 1I use this cross-platform one-liner:
date -d @1267619929 2>/dev/null || date -r 1267619929 It should work both in macOS and modern versions of popular Linux distributions.
You can use this simple awk script:
#!/bin/gawk -f { print strftime("%c", $0); } Sample usage:
$ echo '1098181096' | ./a.awk Tue 19 Oct 2004 03:18:16 AM PDT $ 2Since Bash 4.2 you can use printf's %(datefmt)T format:
$ printf '%(%c)T\n' 1267619929 Wed 03 Mar 2010 01:38:49 PM CET That's nice, because it's a shell builtin. The format for datefmt is a string accepted by strftime(3) (see man 3 strftime). Here %c is:
%cThe preferred date and time representation for the current locale.
Now if you want a script that accepts an argument and, if none is provided, reads stdin, you can proceed as:
#!/bin/bash if (($#)); then printf '%(%c)T\n' "$@" else while read -r line; do printf '%(%c)T\n' "$line" done fi I use this when converting log files or monitoring them:
tail -f <log file> | gawk \ '{ printf strftime("%c", $1); for (i=2; i<NF; i++) printf $i " "; print $NF }' 1In OSX, or BSD, there's an equivalent -r flag which apparently takes a unix timestamp. Here's an example that runs date four times: once for the first date, to show what it is; one for the conversion to unix timestamp with %s, and finally, one which, with -r, converts what %s provides back to a string.
$ date; date +%s; date -r `date +%s` Tue Oct 24 16:27:42 CDT 2017 1508880462 Tue Oct 24 16:27:42 CDT 2017 At least, seems to work on my machine.
$ 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 2I have written a script that does this myself:
#!/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); }' 0In this answer I copy Dennis Williamson's answer and modify it slightly to allow a vast speed increase when piping a column of many timestamps to the script. For example, piping 1000 timestamps to the original script with xargs -n1 on my machine took 6.929s as opposed to 0.027s with this modified version:
#!/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 some example:
$ date Tue Mar 22 16:47:06 CST 2016 $ date -d "Tue Mar 22 16:47:06 CST 2016" "+%s" 1458636426 $ date +%s 1458636453 $ date -d @1458636426 Tue Mar 22 16:47:06 CST 2016 $ date --date='@1458636426' Tue Mar 22 16:47:06 CST 2016
While not pure bash, the following script will convert timestamps of length 13 in a string to their equivalent date in your local timezone using 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" input
{"timestamp":"1573121629939","level":"DEBUG","thread":"http-nio-15372-exec-3","logger":"org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor"} output
$ 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"} I had to convert timestamps inline in my bash history to make sense to me.
Maybe the following coming from an answer to How do I replace a substring by the output of a shell command with sed, awk or such? could be interesting to other readers too. Kudos for the original sed inline code go to @Gabriel.
cat ~/.bash_history | sed "s/^#\([0-9]\+\)$/echo -n '#'; date -u --d @\1 '\+\%Y-\%m-\%d \%T'/e" | less 1If you're looking to format many timestamps all at once, I've written a C util called datefmt that formats timestamps in a text stream:
Let’s say we have some logs that contain unix timestamps:
$ cat logs.txt EVENTS 1638499687 blahblah log1 EVENTS 1638499717 blahblah log2 We can pipe this log into datefmt to convert these timestamps into human-readable dates:
$ <logs.txt datefmt EVENTS 2021-12-02 18:48 blahblah log1 EVENTS 2021-12-02 18:48 blahblah log2 Of course you can customize the format as well:
$ <logs.txt datefmt "DATE:'%m-%d %R'" EVENTS DATE:'12-02 18:48' blahblah log1 EVENTS DATE:'12-02 18:48' blahblah log2 I've packaged this in NixOS, hopefully it will trickle out to other distros soon, but for now you will need to download the tarball and build it with make
In PHP
$unix_time = 1256571985; echo date("Y-m-d H:i:s",$unix_time) 1