I would like to view a text file with awk/grep which contains a Unix timestamp in the first column. How can I convert it to a human-readable time while viewing?
-
It would be nice to have a portable answer to this not relying on perl or gawk. – R.. GitHub STOP HELPING ICE Oct 23 '19 at 19:06
-
5@R.. isn’t Perl portable enough? – Stephen Kitt Oct 23 '19 at 20:54
-
@StephenKitt: No, not at all. From both a standpoint of whether it's installed, and whether it even can be built for your system. But if you're happy with having to build/install software, the portable answer is just a one-line C program. – R.. GitHub STOP HELPING ICE Oct 23 '19 at 21:55
-
@R Is there any Unix-variants (actually used) left for which Perl is not available as a binary? – Thorbjørn Ravn Andersen Oct 25 '19 at 09:55
-
@ThorbjørnRavnAndersen: Saying "not available" is a bit unfair, but SmartOS doesn't come with perl installed. – jesse_b Oct 25 '19 at 14:45
-
@jesse_b I would guess that if you are on a SmartOS machine, you also have root access and could install Perl if you wanted to. – Thorbjørn Ravn Andersen Oct 26 '19 at 11:40
-
@ThorbjørnRavnAndersen: You could also install any number of non-universal applications, hell you could even install microsoft windows if you wanted to. Having root access doesn't mean everything is portable. – jesse_b Oct 26 '19 at 12:59
-
@jesse_b so yes... what is then the baseline you would think appropriate. POSIX? Ancient system V? – Thorbjørn Ravn Andersen Oct 28 '19 at 10:55
-
POSIX is the standard that everyone, not just myself, thinks is appropriate. However I don't think there are very many things, if anything at all, that is truly portable. – jesse_b Oct 28 '19 at 12:55
-
@Jesse_b Then I think the only trivial solution is to compile and run a suitable C program. – Thorbjørn Ravn Andersen Oct 30 '19 at 09:38
7 Answers
If the line starts with the unix timestamp, then this should do it:
perl -pe 's/^(\d+)/localtime $1/e' inputfilename
perl -p
invokes a loop over the expression passed with -e
which is executed for each line of the input, and prints the buffer at the end of the loop.
The expression uses the substition command s///
to match and capture a sequence of digits at the beginning of each line, and replace it with the local time representation of those digits interpreted as a unix timestamp. /e
indicates that the replacement pattern is to be evaluated as an expression.

- 16,115
-
4Or
perl -MPOSIX -pe 's/^\s*\K\d+/strftime "%FT%T%z", localtime $&/e'
to get a more useful timestamp format (unambiguous and sorts lexically the same as chronologically) – Stéphane Chazelas Oct 23 '19 at 10:18
If your AWK is Gawk, you can use strftime
:
gawk '{ print strftime("%c", $1) }'
will convert the timestamp in the first column to the current locale’s default date/time representation.
You can use this to transform the content before viewing it:
gawk '{ print gensub($1, strftime("%c", $1), 1) }' inputfile

- 434,908
use "date"
You don't need perl, awk, php, or a long arithmetic expression for this. You can do it with gnu "date", which is really quite useful for this sort of thing. For other versions of "date", your YMMV.
$ date -d '1/1/1970 GMT 1571889039 seconds'
Wed Oct 23 20:50:39 PDT 2019
What's going on here is that you are specifying a time and an adjustment to it. The time is midnight January 1st, 1970 GMT, the unix epoch. (Midnight is not explicitly given; it's used implicitly any time you omit the time of day.)
The adjustment, 1571889039 seconds, is added to the time. Use your timestamp instead, obviously. The docs use the word "relative" for this feature.
There's a more concise version, documented only by an example in the manpage, which works for newer versions of gnu date:
$ date -d @2147483647
Mon Jan 18 19:14:07 PST 2038
If you need to manipulate dates often, get to know your date command. It's more than just a clock; it's a date/time library for the shell.
-
1So how do you extract the first column of a text file and convert it with
date
? – Freddy Oct 24 '19 at 05:34 -
-
-
It outputs the date-time in the system timezone. What do I need to do in order to get the date-time always in UTC? – Arvind Kumar Avinash Jul 02 '21 at 17:40
As Dan mentions in his answer, the Gnu date(1)
command can be
given a -d
parameter with a date or timestamp that it will treat as
the date to be output. (This is not available in the POSIX or BSD
date(1)
commands, however.) @1571806800
is the format used to
specify a time_t
integer.
Here's a Bash shell function that acts as a filter, reading lines from the input, assuming any word starting a line that's all digits is a timestamp, and converting that to human-readable output in one of my favourite formats.
ts2hr() {
while read n rest; do
if [[ $n =~ ^[0-9][0-9]*$ ]]; then
echo "$(date -d @"$n" +"%Y-%m-%d %T")" "$rest"
else
echo "$n" "$rest"
fi
done
}
Here's what some input and output look like:
ts2hr <<____
1571806123 first line
# A comment?
1571720456 second date's here
Just a regular sentence.
1571547789 The last line.
____
2019-10-23 13:48:43 first line
# A comment?
2019-10-22 14:00:56 second date's here
Just a regular sentence.
2019-10-20 14:03:09 The last line.
You can tweak the function as necessary to handle the particular input
and output formats you require, as well as the tools you have
available. The above function is Bash mainly because the =~
operator
made the pattern match easier; if you need this in Bourne shell you'll
have to code the check differently, if indeed you need it at all.

- 670
For a portable version of this, in the worst case you can do the math yourself. Unix timestamps are defined in POSIX XBD 4.16 Seconds Since the Epoch:
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
This is the inverse of the mapping you want, so a little bit of work* is required to reverse it. This will get you to broken-down "POSIX UTC", but then you may need a way to format it in the current timezone. It appears date -d
is not portable, so I'm not clear on whether there's any good way to do this.
* Ok that may be an understatement.
If you don't have gnu date or access to a programming language with strftime or equivalent, you have to do the math yourself, which goes into code golf territory.
unix_to_iso_utc () {
local day_unix=$(($1 / 86400))
local day_offset=$(($1 % 86400))
local d=$(($day_unix + 719468))
local y=$((($d - ($d+2+3*$d/146097)/1461 + ($d-$d/146097)/36524 - ($d+1)/146097)/365))
local y_d=$((365*$y + $y/4 - $y/100 + $y/400))
local y_offset=$(($d - $y_d))
local m=$((($y_offset - ($y_offset+20)/50) / 30))
local m_d=$((30*$m + 3*($m+4)/5 - 2))
local day=$(($y_offset - $m_d + 1))
local m_cont=$((12*$y + $m + 2))
local year=$(($m_cont/12))
local month=$(($m_cont%12 + 1))
local hour=$(($day_offset / 3600))
local hour_offset=$(($day_offset % 3600))
local minute=$(($hour_offset / 60))
local second=$(($hour_offset % 60))
DATE=$(printf "%04d-%02d-%02dT%02d:%02d:%02d" $year $month $day $hour $minute $second)
}
You also probably don't have a timezone database at that point, which can be a huge practical problem, unless you can hardcode what you need.

- 21
As has been said, theres not really a portable way to do this using shell, or
even AWK. GAWK can do it, but GAWK strftime
is not availble with certain
versions of AWK, namely MAWK. And MAWK is used with some popular distros, for
example Debian.
I agree that a portable shell or AWK solution should be available for this. But as its not, and likely wont be for many years, if ever, the best solution is to just use a programming language. Perl has been suggested, another option is PHP:
$ cat input.txt
1571806800 blue
1571720400 green
1571634000 orange
1571547600 red
1571461200 yellow
$ cat app.php
<?php
$r1 = fopen('input.txt', 'r');
while (true) {
$s1 = fgets($r1);
if ($s1 === false) {
break;
}
$a1 = explode(' ', $s1);
$n1 = + $a1[0];
echo date(DATE_W3C, $n1), "\n";
}
$ php app.php
2019-10-23T05:00:00+00:00
2019-10-22T05:00:00+00:00
2019-10-21T05:00:00+00:00
2019-10-20T05:00:00+00:00
2019-10-19T05:00:00+00:00

- 1
- 5
- 44
- 63