Perl script to convert logged datetimes to UNIX epoch timestamps - perl

I have a log file (datetimes.log) consisting of hundreds of thousands of timestamps of the form:
YYYY-MM-DD HH:mm:ss
For example:
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03
...etc.
I'd like to write a simple Perl script to output a new unix_timestamps.log file that contains the same entries, but instead of the datetime, to have the corresponding UNIX epoch timestamp. For the example above, the unix_timestamps.log file would have the following info in it:
1364453031
1364453035
1364453043
...etc.
The only thing I can think of is perl convert_2_timestamps.pl:
#!/usr/bin/perl
use warnings;
use strict;
grep m/_(\d{4})(\d\d)(\d\d)/ | POSIX::mktime(?, ?, ?, ?, ?, ?) > unix_timestamps.log
But not sure how to transfer the parameters into mktime, and not sure if this is even the right approach. Thanks in advance.

use strict;
use warnings;
use DateTime::Format::Strptime;
my $parser = DateTime::Format::Strptime->new(
pattern => '%Y-%m-%d %H:%M:%S',
on_error => 'croak',
);
while( <DATA> ) {
my $dt = $parser->parse_datetime($_);
print $dt->epoch, "\n";
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03

This is a perfect use for the Time::Piece module which has been a standard part of the Perl distribution for over five years.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
# Read the data a record at a time. Data ends up in $_.
# N.B. Using built-in DATA filehandle for this demo.
# In the real world you'd open a separate filehandle.
while (<DATA>) {
chomp;
# Create a Time::Piece object using strptime (that's "string
# parse time") and immediately call the epoch method on the
# new object to get the value you want.
say Time::Piece->strptime($_, '%Y-%m-%d %H:%M:%S')->epoch;
}
__DATA__
2013-03-28 06:43:51
2013-03-28 06:43:55
2013-03-28 06:44:03

You could break up the YYYY-MM-DD HH:mm:ss format like so:
my ( $y, $m, #t ) = split /[-: ]+/, $time_str;
my $time = mktime( reverse #t, $m - 1, $y - 1900 );
But you could also put it in a replace like so:
s{(\d{4})-(0?[1-9]\d?)-(0?[1-9]\d?) (0?\d{1,2}):(0?\d{1,2}):(0?\d{1,2})}{
mktime( $6, $5, $4, $3, $2 - 1, $1 - 1900 )
}e;

Try the Date::Parse CPAN module. (http://metacpan.org/pod/Date::Parse)
With it, your convert_2_timestamps.pl can be just:
#!/usr/bin/perl
use warnings;
use strict;
use Date::Parse;
while (<>) {
chomp;
printf("%s\n", str2time("$_ GMT"));
}
Note that I had to append GMT to your example input to get your expected output.
Run as:
perl convert_2_timestamps.pl < datetimes.log > unix_timestamps.log

Related

Perl Format dates

use Date::Calc qw(:all);
use Time::Piece;
use POSIX qw(strftime);
$a1 = '01.01.1963';
($year, $month, $day) = Decode_Date_US($a1);
print "$year $month $day\n";
$formatted = strftime('%m/%d/%Y',$month,$day,$year);
print "$formatted\n";
I am trying to format dates in a consistent format using POSIX(strftime). I am uncertain what the input format might be. I am using Decode_Date_US to extract the relevant year, month, day information. I am then trying to format the dates in consistent manner using strftime. I am getting following error
Usage: POSIX::strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) at test_dates.pl line 60
Any help would appreciated.
"use Time::Piece" would be eventually used to sort the dates.
Thanks
Just use Time::Piece and strptime
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $date = '01.01.1963';
my $timestamp = Time::Piece->strptime( $date, "%m.%d.%Y" );
print $timestamp -> strftime( "%m/%d/%Y")
But if the format is inconsistent, then you're onto a loser - for starters, there's plenty of places that transpose day/month ordering, or represent year as two digits (that sometimes will clash with month or day).
It's inherently ambiguous. You can - at best - apply some very crude guessing by grabbing groups of digits and assuming that they're in a consistent order.
E.g.
my ( $day, $month, $year ) = m/(\d{2}).*(\d{2}).*(\d{4})/;
$timestamp = Time::Piece -> strptime ( "$year-$month-$day", "%Y-%m-%d" );
But you'll be tripped up by dates like 10/11/12 because you simply can't know which number is which field. You can try guessing, by evaling the strptime and just retrying different formats until you get one that does decode to something valid.
As you indicate - Decode_Date_US basically does this so:
use strict;
use warnings;
use Date::Calc qw(:all);
use Time::Piece;
my $a1 = '01.01.1963';
my ($year, $month, $day) = Decode_Date_US($a1);
my $time = Time::Piece -> strptime("$year/$month/$day", "%Y/%m/%d");
print $time->strftime("%Y-%m-%d"),"\n";
Also - use strict; use warnings; is good.
And - there's one correct way to write dates. If you're going to reformat at all, then the one that isn't ambiguous is the best choice.
I ended up using DateTime module's strftime function which can handle dates earlier than 1970.
"Crashing" -Perl command line interpreter has stopped working. If it helps, I am using a windows machine and a very infrequent perl user.
this worked for me
use Date::Calc qw(:all);
use DateTime;
$dateformat = "%m/%d/%Y";
($year, $month, $day) = Decode_Date_US($date);
$date = DateTime->new(
year=>$year,
month=>$month,
day=>$day,
);
$date = $date->strftime($dateformat);

Convert specific number date to show month

Want to convert for example that date:
02082012
In that case:
02 - Day
08 - Month
2012 - Year
For now I separate the date but not able to convert into month:
#echo "02082012"|gawk -F "" '{print $1$2 "-" $3$4 "-" $5$6$7$8}'
#02-08-2012
Expected view after convert and to catch all Months:
02-Aug-2012
straightforward:
kent$ date -d "$(echo '02082012'|sed -r 's/(..)(..)(....)/\3-\2-\1/')" "+%d-%b-%Y"
02-Aug-2012
Another Perl sollution with the POSIX module, which is in the Perl core.
use POSIX 'strftime';
my $date = '02082012';
print strftime( '%d-%b-%Y', 0, 0, 0,
substr( $date, 0, 2 ),
substr( $date, 2, 2 ) - 1,
substr( $date, 4, 4 ) - 1900 );
Look at http://strftime.net/ for a very nice overview of what the placeholders to strftime do.
Using Perl’s POSIX module and strftime looks like
#! /usr/bin/env perl
use strict;
use warnings;
use POSIX qw/ strftime /;
while (<>) {
chomp;
if (my($d,$m,$y) = /^(\d\d)(\d\d)(\d\d\d\d)$/) {
print strftime("%d-%b-%Y", 0, 0, 0, $d, $m-1, $y-1900), "\n";
}
}
Output:
$ echo 02082012 | convert-date
02-Aug-2012
Time::Piece is a core Perl module and is great for simple manipulations like this.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $string = '02082012';
my $date = Time::Piece->strptime($string, '%d%m%Y');
say $date->strftime('%d-%b-%Y');
(Yes, this is very similar to user1811486's answer - but it uses the correct formats as requested in the original question.)
I think like this.....
use 5.10;
use strict;
use warnings;
use Time::Piece;
my $date = '2013-04-07';
my $t = Time::Piece->strptime($date, '%Y-%m-%d');
print $t->month;
print $t->strftime('%Y-%b-%d');
Just I tried this ...
To break apart a string with fixed field lengths, use unpack:
my $input = "02082012";
my ( $day, $month, $year ) = unpack( 'a2 a2 a4', $input );
print "$input becomes $day, $month, $year\n";
See http://perldoc.perl.org/functions/unpack.html
Then, as stated in the other answers, use POSIX::strftime() to reformat the date.

Today's Date in Perl in MM/DD/YYYY format

I'm working on a Perl program at work and stuck on (what I think is) a trivial problem. I simply need to build a string in the format '06/13/2012' (always 10 characters, so 0's for numbers less than 10).
Here's what I have so far:
use Time::localtime;
$tm=localtime;
my ($day,$month,$year)=($tm->mday,$tm->month,$tm->year);
You can do it fast, only using one POSIX function. If you have bunch of tasks with dates, see the module DateTime.
use POSIX qw(strftime);
my $date = strftime "%m/%d/%Y", localtime;
print $date;
You can use Time::Piece, which shouldn't need installing as it is a core module and has been distributed with Perl 5 since version 10.
use Time::Piece;
my $date = localtime->strftime('%m/%d/%Y');
print $date;
output
06/13/2012
Update
You may prefer to use the dmy method, which takes a single parameter which is the separator to be used between the fields of the result, and avoids having to specify a full date/time format
my $date = localtime->dmy('/');
This produces an identical result to that of my original solution
use DateTime qw();
DateTime->now->strftime('%m/%d/%Y')
expression returns 06/13/2012
If you like doing things the hard way:
my (undef,undef,undef,$mday,$mon,$year) = localtime;
$year = $year+1900;
$mon += 1;
if (length($mon) == 1) {$mon = "0$mon";}
if (length($mday) == 1) {$mday = "0$mday";}
my $today = "$mon/$mday/$year";
use Time::Piece;
...
my $t = localtime;
print $t->mdy("/");# 02/29/2000
Perl Code for Unix systems:
# Capture date from shell
my $current_date = `date +"%m/%d/%Y"`;
# Remove newline character
$current_date = substr($current_date,0,-1);
print $current_date, "\n";
Formating numbers with leading zero is done easily with "sprintf", a built-in function in perl (documentation with: perldoc perlfunc)
use strict;
use warnings;
use Date::Calc qw();
my ($y, $m, $d) = Date::Calc::Today();
my $ddmmyyyy = sprintf '%02d.%02d.%d', $d, $m, $y;
print $ddmmyyyy . "\n";
This gives you:
14.05.2014

In Perl, how can I find the day of the week which corresponds to a given date?

I am trying to convert given dates to the corresponding days of the week using Perl with Date::Day.
The input string is in the format: October 24, 2011; March 12, 1989; November 26, 1940.
I have written a script which will parse the above input and convert each date to a format which will be accepted by Date::Day::day().
This subroutine accepts the input in format, mm,dd,yyyy. I have done this using hashes. Recently posted a thread on this query on stackoverflow and with the help of other members, was able to do it.
Here's my script and it returns me ERR for each of the dates instead of returning the Day of Week corresponding to the date.
There seems to be something wrong with the input format of the parameter passed to day() subroutine.
Here's more documentation on the Perl Module I am using:
http://helpspy.com/c.m/programming/lang/perl/cpan/c06/Date/Day/d_1/
I am interested to know, where exactly I am going wrong. Do I have to make some modifications to the date before passing it as a parameter to the day() subroutine?
#!/usr/bin/perl
use Date::Day;
use strict;
use warnings;
my #arr;
print "Enter the string: ";
my $str=<>;
chomp $str;
my #dates= split /; /,$str;
my %days= ("January",1,"February",2,"March",3,"April",4,"May",5,"June",6,"July",7,"August",8,"September",9,"October",10,"November",11,"December",12);
my #output = map {
my $pattern=$_;
$pattern =~ s/(\S*)\s/$days{$1}, /;
$pattern =~ s/\s//g;
$pattern
} #dates;
print &day(11,9,1987); # for test purpose and it returns correct value
foreach $output (#output)
{
chomp $output;
my $result=&day($output);
push(#arr,$result);
}
foreach my $arr (#arr)
{
print $arr."; ";
}
The output of the above script is: ERR; ERR; ERR;
Date::Day looks like a rather old module. It was last updated almost nine years ago. That's not to say that it's broken, but these days the DateTime family of modules handle pretty much any date/time processing that you want. I'd strongly recommend taking a look at those instead.
Here's an example solving your problem using DateTime::Format::Strptime.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use DateTime::Format::Strptime;
my $dt_parser = DateTime::Format::Strptime->new(
pattern => '%B %d, %Y'
);
while (<DATA>) {
chomp;
my $dt = $dt_parser->parse_datetime($_);
say $dt->day_name;
}
__END__
October 24, 2011
March 12, 1989
November 26, 1940
You're passing a string to the sub &day.
Here is a rewrite :
#!/usr/local/bin/perl
use Data::Dump qw(dump);
use strict;
use warnings;
use Date::Day;
print "Enter the string: ";
my $str=<>;
chomp $str;
my #dates= split /; /,$str;
my %days = ("January",1,"February",2,"March",3,"April",4,"May",5,"June",6,"July",7,"August",8,"September",9,"October",10,"November",11,"December",12);
my #output = map {
my #l = split/[ ,]+/;
$l[0] = $days{$l[0]};
[#l];
} #dates;
my #arr;
foreach my $date(#output) {
push #arr, &day(#$date);
}
dump#arr;
output:
("MON", "SUN", "TUE")

How to change ctime to normal string representation?

Using File::stat we can get the ctime of a given file. My question is how to change the ctime, which means the inode change time in seconds since the epoch, to a normal time representation like "2009-08-26 17:28:28". Is there any build-in or module can solve this task?
The most standard way is to use POSIX module and it's strftime function.
use POSIX qw( strftime );
use File::stat;
my $stat_epoch = stat( 'some_file.name' )->ctime;
print strftime('%Y-%m-%d %H:%M:%S', localtime( $stat_epoch ) );
All these markers like %Y, %m and so on, are defined in standard, and work the same in C, system "date" command (at least on Unix) and so on.
If all you want is a human-readable representation, then
print scalar localtime stat($filename)->ctime;
will do the job. This prints something like "Wed Jun 10 19:25:16 2009".
You can't influence the format, though.
If you want the time in GMT, use "scalar gmtime" instead.
This is a special behaviour of localtime and gmtime in scalar context.
use DateTime;
$dt = DateTime->from_epoch( epoch => $epoch );
The datetime object then contains the representations you require, e.g. $year = $dt->year; etc. In scalar context you get a nice human-readable representation, e.g.
$epoch = 123456789;
$dt = DateTime->from_epoch( epoch => $epoch );
print $dt;
1973-11-29T21:33:09
use File::stat;
use Time::CTime;
$file = "BLAH BLAH BLAH";
$st = stat($file) or die "No $file: $!";
print strftime('%b %o', localtime($st->ctime));
#Feb 11th, for example.
As you can see from the number of answers here, you have lots of options. I like the Date::Format module:
#!/usr/bin/perl
use strict;
use warnings;
use Date::Format;
use File::Stat;
my $fs = File::Stat->new( '.vimrc' );
my $mtime = $fs->ctime();
print time2str( "changed in %Y on %B, %o at %T\n", $mtime );
First, are you really using File::Stat rather than File::stat? If so, and if you have 5.8 or greater, switch to File::stat.
perldoc localtime
localtime EXPR
localtime
Converts a time as returned by the time function to a 9-element list with the time analyzed for the local time zone.
...
In scalar context, localtime() returns the ctime(3) value:
Once you realize thatlocaltime can take an argument, then your mind opens up to all the other possibilities mentioned in this thread.
#!/usr/bin/perl
use strict;
use warnings;
use File::stat;
my $stat = stat 't.pl';
print "$_\n" for $stat->ctime, scalar localtime($stat->ctime);
There's an example in Time::localtime perldoc for using it's ctime() to do this sort of thing.
use File::stat;
use Time::localtime;
my $date_string = ctime(stat($file)->ctime);