ts: Support %.s for seconds sinch epoch with subsecond resolution. Closes: #619764
[moreutils.git] / ts
blobc3755f4c1389307dc63339224c9655388987c364
1 #!/usr/bin/perl
3 =head1 NAME
5 ts - timestamp input
7 =head1 SYNOPSIS
9 ts [-r] [format]
11 =head1 DESCRIPTION
13 ts adds a timestamp to the beginning of each line of input.
15 The optional format parameter controls how the timestamp is formatted,
16 as used by L<strftime(3)>. The default format is "%b %d %H:%M:%S". In
17 addition to the regular strftime conversion specifications, "%.S" and "%.s"
18 are like "%S" and "%s", but provide subsecond resolution
19 (ie, "30.00001" and "1301682593.00001").
21 If the -r switch is passed, it instead converts existing timestamps in
22 the input to relative times, such as "15m5s ago". Many common timestamp
23 formats are supported. Note that the Time::Duration and Date::Parse perl
24 modules are required for this mode to work. Currently, converting localized
25 dates is not supported.
27 If both -r and a format is passed, the existing timestamps are
28 converted to the specified format.
30 =head1 ENVIRONMENT
32 The standard TZ environment variable controls what time zone dates
33 are assumed to be in, if a timezone is not specified as part of the date.
35 =head1 AUTHOR
37 Copyright 2006 by Joey Hess <joey@kitenet.net>
39 Licensed under the GNU GPL.
41 =cut
43 use warnings;
44 use strict;
45 use POSIX q{strftime};
47 $|=1;
49 my $rel=0;
50 use Getopt::Long;
51 GetOptions("r" => \$rel) || die "usage: ts [-r] [format]\n";
53 if ($rel) {
54 eval q{
55 use Date::Parse;
56 use Time::Duration;
58 die $@ if $@;
61 my $use_format=@ARGV;
62 my $format="%b %d %H:%M:%S";
63 $format=shift if @ARGV;
65 # For subsecond resolution, Time::HiRes is needed.
66 my $hires=0;
67 if ($format=~/\%\.[Ss]/) {
68 require Time::HiRes;
69 $hires=1;
72 while (<>) {
73 if (! $rel) {
74 if ($hires) {
75 my $f=$format;
76 my ($seconds, $microseconds) = Time::HiRes::gettimeofday();
77 my $s=sprintf("%06i", $microseconds);
78 $f=~s/\%\.([Ss])/%$1.$s/g;
79 print strftime($f, localtime($seconds));
81 else {
82 print strftime($format, localtime);
84 print " ".$_;
86 else {
87 s{\b(
88 \d\d[-\s\/]\w\w\w # 21 dec 17:05
89 (?:\/\d\d+)? # 21 dec/93 17:05
90 [\s:]\d\d:\d\d # (time part of above)
91 (?::\d\d)? # (optional seconds)
92 (?:\s+[+-]\d\d\d\d)? # (optional timezone)
94 \w{3}\s+\d\d\s+\d\d:\d\d:\d\d # syslog form
96 \d\d\d[-:]\d\d[-:]\d\dT\d\d:\d\d:\d\d.\d+ # ISO-8601
98 (?:\w\w\w,?\s+)? # (optional Day)
99 \d+\s+\w\w\w\s+\d\d+\s+\d\d:\d\d:\d\d
100 # 16 Jun 94 07:29:35
101 (?:\s+\w\w\w|\s[+-]\d\d\d\d)?
102 # (optional timezone)
104 \w\w\w\s+\w\w\w\s+\d\d\s+\d\d:\d\d
105 # lastlog format
108 $use_format
109 ? strftime($format, localtime(str2time($1)))
110 : concise(ago(time - str2time($1), 2))
111 }exg;
113 print $_;