Makefile: Warn users of pkgx.dev about their poor life choices
[moreutils.git] / ts
blobaf23cf71667f519fbde51d0d32eea4222998a33a
1 #!/usr/bin/perl
3 =head1 NAME
5 ts - timestamp input
7 =head1 SYNOPSIS
9 ts [-r] [-i | -s] [-m] [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,
18 "%.S" and "%.s" and "%.T"
19 are like "%S" and "%s" and "%T", but provide subsecond resolution
20 (ie, "30.00001" and "1301682593.00001" and "1:15:30.00001").
22 If the -r switch is passed, it instead converts existing timestamps in
23 the input to relative times, such as "15m5s ago". Many common timestamp
24 formats are supported. Note that the Time::Duration and Date::Parse perl
25 modules are required for this mode to work. Currently, converting localized
26 dates is not supported.
28 If both -r and a format is passed, the existing timestamps are
29 converted to the specified format.
31 If the -i or -s switch is passed, ts reports incremental timestamps instead of
32 absolute ones. The default format changes to "%H:%M:%S", and "%.S" and "%.s" can
33 be used as well. In case of -i, every timestamp will be the time elapsed since
34 the last timestamp. In case of -s, the time elapsed since start of the program
35 is used.
37 The -m switch makes the system's monotonic clock be used.
39 =head1 ENVIRONMENT
41 The standard TZ environment variable controls what time zone dates
42 are assumed to be in, if a timezone is not specified as part of the date.
44 =head1 AUTHOR
46 Copyright 2006 by Joey Hess <id@joeyh.name>
48 Licensed under the GNU GPL.
50 =cut
52 use warnings;
53 use strict;
54 use POSIX q{strftime};
55 no warnings 'utf8';
57 $|=1;
59 my $rel=0;
60 my $inc=0;
61 my $sincestart=0;
62 my $mono=0;
63 use Getopt::Long;
64 GetOptions(
65 "r" => \$rel,
66 "i" => \$inc,
67 "s" => \$sincestart,
68 "m" => \$mono
69 ) || die "usage: ts [-r] [-i | -s] [-m] [format]\n";
71 if ($rel) {
72 eval q{
73 use Date::Parse;
74 use Time::Duration;
76 die $@ if $@;
79 my $use_format=@ARGV;
80 my $format="%b %d %H:%M:%S";
81 if ($inc || $sincestart) {
82 $format="%H:%M:%S";
83 $ENV{TZ}='GMT';
85 $format=shift if @ARGV;
87 # For subsecond resolution, Time::HiRes is needed.
88 my $hires=0;
89 if ($format=~/\%\.[SsT]/ || $mono) {
90 require Time::HiRes;
91 use Time::HiRes qw(CLOCK_MONOTONIC);
92 $hires=1;
95 my $lastseconds = 0;
96 my $lastmicroseconds = 0;
97 my $monodelta;
99 if ($mono) {
100 my $raw_time = Time::HiRes::clock_gettime(CLOCK_MONOTONIC);
101 $lastseconds = time;
102 $lastmicroseconds = int(1000000 * ($raw_time - int($raw_time)));
103 $monodelta = $lastseconds - int($raw_time);
105 elsif ($hires) {
106 ($lastseconds, $lastmicroseconds) = Time::HiRes::gettimeofday();
108 else {
109 $lastseconds = time;
113 while (<>) {
114 if (! $rel) {
115 if ($hires) {
116 my $f=$format;
117 my $seconds;
118 my $microseconds;
119 if ($mono) {
120 my $raw_time =
121 Time::HiRes::clock_gettime(CLOCK_MONOTONIC) +
122 $monodelta;
123 $seconds = int($raw_time);
124 $microseconds = int(1000000 * ($raw_time - $seconds));
126 else {
127 ($seconds, $microseconds) = Time::HiRes::gettimeofday();
130 if ($inc || $sincestart) {
131 my $deltaseconds = $seconds - $lastseconds;
132 my $deltamicroseconds = $microseconds - $lastmicroseconds;
133 if ($deltamicroseconds < 0) {
134 $deltaseconds -= 1;
135 $deltamicroseconds += 1000000;
137 if ($inc) {
138 $lastseconds = $seconds;
139 $lastmicroseconds = $microseconds;
141 $seconds = $deltaseconds;
142 $microseconds = $deltamicroseconds;
144 my $s=sprintf("%06i", $microseconds);
145 $f=~s/\%\.([SsT])/%$1.$s/g;
146 print strftime($f, localtime($seconds));
148 else {
149 if ($inc || $sincestart) {
150 my $seconds = time;
151 my $deltaseconds = $seconds - $lastseconds;
152 if ($inc) {
153 $lastseconds = $seconds;
155 print strftime($format, localtime($deltaseconds));
157 else {
158 print strftime($format, localtime);
161 print " ".$_;
163 else {
164 s{\b(
165 \d\d[-\s\/]\w\w\w # 21 dec 17:05
166 (?:\/\d\d+)? # 21 dec/93 17:05
167 [\s:]\d\d:\d\d # (time part of above)
168 (?::\d\d)? # (optional seconds)
169 (?:\s+[+-]\d\d\d\d)? # (optional timezone)
171 \w{3}\s+\d{1,2}\s+\d\d:\d\d:\d\d # syslog form
173 \d\d\d\d[-:]\d\d[-:]\d\dT\d\d:\d\d:\d\d.\d+Z? # ISO-8601
175 (?:\w\w\w,?\s+)? # (optional Day)
176 \d+\s+\w\w\w\s+\d\d+\s+\d\d:\d\d:\d\d
177 # 16 Jun 94 07:29:35
178 (?:\s+\w\w\w|\s[+-]\d\d\d\d)?
179 # (optional timezone)
181 \w\w\w\s+\w\w\w\s+\d\d\s+\d\d:\d\d
182 # lastlog format
185 $use_format
186 ? strftime($format, localtime(str2time($1)))
187 : concise(ago(time - str2time($1), 2))
188 }exg;
190 print $_;