How to calculate date difference in perl - perl

I am a novice in perl scripting. I have a requirement where in I need to find the difference of two dates in the minutes/seconds
$date1 = Fri Aug 30 10:53:38 2013
$date2 = Fri Aug 30 02:12:25 2013
can you tell me how do we achieve this, Parsing , calculation , modules req and all
Thanks
Goutham

Time::Piece has been a standard part of Perl since 2007.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;
my $date1 = 'Fri Aug 30 10:53:38 2013';
my $date2 = 'Fri Aug 30 02:12:25 2013';
my $format = '%a %b %d %H:%M:%S %Y';
my $diff = Time::Piece->strptime($date1, $format)
- Time::Piece->strptime($date2, $format);
say $diff;

Convert both dates to UNIX time
See http://metacpan.org/pod/Date::Parse
Then you can do a simple mathematical subtraction to find the number of seconds between the two.
Then it is simple maths all the way to get minutes, hours, etc.

Related

How to calculate a date a week ago from today

I wanna calculate the date a week ago from today with a specific format and put it in to a variable. For example, today is Nov 21st. 2014, and I wanna print out: Last week is 2014-11-14.
I know we can use Date::Calc module, but I don't know how.
Check Time::Piece and Time::Seconds core modules,
use Time::Piece;
use Time::Seconds;
my $t = localtime() - ONE_WEEK;
print $t->ymd;
output
2014-11-14
DateTime version
use DateTime;
my $now = DateTime->now(time_zone => 'local')->subtract(weeks => 1);
print $now->ymd, ' ',$now->hms;
Date::Calc version
Instead of one week you can subtract 7 days using Date::Calc module
use Date::Calc qw(Add_Delta_Days);
my #date = Add_Delta_Days( 2014, 11, 21, -7 );
print join('-', #date);
OUTPUT
2014-11-14
This is very simple using Date::Manip
use Date::Manip;
my $today = ParseDate("today");
my $weeksago = DateCalc($today,"-7d");
Why not just subtract X days from the "mday" field of localtime? This example shows subtracting 60 days from the end of august. I'm not sure who corrects the month but I think I'm getting the right answer...
$ date
Wed Aug 30 14:34:14 DFT 2017
$ perl -MPOSIX -e '#t=localtime time; $t[3] -= 60; print strftime( "%Y/%m/%d", #t), "\n";'
2017/07/01

perl print current year in 4 digit format

how do i get the current year in 4 digit this is what i have tried
#!/usr/local/bin/perl
#months = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
#days = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
$year = $year+1900;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
print "DBR_ $year\\$months[$mon]\\Failures_input\\Failures$mday$months[$mon].csv \n";
This prints DBR_ 114\Apr\Failures_input\Failures27Apr.csv
How do I get 2014?
I am using version 5.8.8 build 820.
use Time::Piece;
my $t = Time::Piece->new();
print $t->year;
Move the line:
$year = $year+1900;
To after that call to localtime() and to become:
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
$year = $year+1900;
The best way is to use the core library Time::Piece. It overrides localtime so that the result in scalar context is a Time::Piece object, you can use the many methods that the module supplies on it. (localtime in list context, as you have used it in your own code, continues to provide the same nine-element list.)
The strftime method allows you to format a date/time as you wish.
This very brief program produces the file path that I think you want (I doubt if there should be a space after DBR_?) Note that there is no need to double up backslashes inside a single-quoted string unless it is the last character of the string.
use strict
use warnings;
use Time::Piece;
my $path = localtime->strftime('DBR_%Y\%b\Failures_input\Failures%m%d.csv');
print $path;
output
DBR_2014\Apr\Failures_input\Failures27Apr.csv
One option to get the 4 digit year:
#!/usr/bin/perl
use POSIX qw(strftime);
$year = strftime "%Y", localtime;
printf("year %02d", $year);
You can also use
my ($y,$m,$d) = Date::Calc::Today();
$y variable will contain 2019
$m variable will contain 8
$d variable will contain 9
at the time of writing this answer ( 9th August 2019 )
The simplest way, I find, to get the year is:
my $this_year = (localtime)[5] + 1900;

getting minutes difference between two Time::Piece objects

I have the code:
use Time::Piece;
use Time::Seconds;
my $timespan = $latest_time - $timestamp;
print $latest_time . "\n";
print $timestamp . "\n";
print $timespan->minutes;
where $latest_time = Time::Piece->new; and $timestamp = Time::Piece->strptime();
and I get the results:
Thu Mar 27 09:40:19 2014
Thu Mar 27 09:40:00 2014
-479.683333333333
What went wrong? there should be 0 minutes for $timespan, correct? Where is -479 coming from?
Reproducing the "bug"
This issue arises because strptime defaults to UTC instead of to the local timezone. This can be demonstrated in the following code which takes a current time, prints it out, then reparses it and shows the difference:
use strict;
use warnings;
use Time::Piece;
my $now = Time::Piece->new();
print $now->strftime(), "\n";
my $fmt = "%Y-%m-%d %H:%M:%S";
my $nowstr = $now->strftime($fmt);
my $parsed = Time::Piece->strptime("$nowstr", $fmt);
print "($nowstr)\n";
print $parsed->strftime(), "\n";
my $diff = $now - $parsed;
print $diff->hours, " hours difference\n";
Outputs:
Wed, 26 Mar 2014 21:42:08 Pacific Daylight Time
(2014-03-26 21:42:08)
Wed, 26 Mar 2014 21:42:08 UTC
7 hours difference
One hackish solution - getting parsed times to read as local
Now, in hacking around, I've discovered one potential hack for this on my strawberry perl system. It's by calling strptime like this: $now->strptime.
my $nowstr = "2014-03-26 21:51:00"; #$now->strftime($fmt);
my $parsed = $now->strptime("$nowstr", $fmt); #Time::Piece->strptime("$nowstr", $fmt);
print "($nowstr)\n";
print $parsed->strftime(), "\n";
my $diff = $now - $parsed;
print $diff->hours, " hours difference\n";
To confirm that strptime was actually using the time I set it, I gave it one that was 6 minutes before the current time. The output is as follows:
Wed, 26 Mar 2014 21:57:00 Pacific Daylight Time
(2014-03-26 21:51:00)
Wed, 26 Mar 2014 21:51:00 Pacific Standard Time
0.1 hours difference
The parsed time will inherit the c_islocal value from $now. $now just needs to be initialized with either localtime or ->new() and not gmtime of course.
As you can see one claims DST while the other does not, but date math is still done correctly. I was able to figure out this hack by looking at the source for strptime, _mktime, and new.
Hopefully, at the very least my code to reproduce the error will be helpful to someone with more experience with Time::Piece, and I'd love a better solution.
When I use strftime("%H:%M:%S %Z") for both $latest_time and $timestamp they both show the same timezone, but the $latest_time - $timestamp operation shows that there is difference between the timezones as tobyink pointed out. This might be a bug in Time::Piece module.
So it seems that Time::Piece->new; gets the current machine time including the timezone.
So either I fix the timezone in Time::Piece->new or include a timezone value when I use Time::Piece->strptime(); to fix the timezone problem. Thanks for the info, tobyink.

Perl code to change the date format from IST/UTC to YYYY-MM-DD format

Input:
$str="Thu Mar 25 01:48:45 IST 2011";
Desired output:
2011-03-25
I want only date, not the time.
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
my $tstamp = Time::Piece->strptime
("Thu Mar 25 01:48:45 2011", "%a %b %d %H:%M:%S %Y");
print $tstamp->strftime("%Y-%m-%d\n");
use Date::Manip;
$str =~ s/[[:upper:]]{3}//; # Remove timezone
$d = ParseDate($str);
die "Invalid date\n" unless $d;
$d=~s/(....)(..)(..).*/$1-$2-$3/;
print "$d\n";
Heck, if you know the format of the date, you don't even need to use a Perl module to manipulate the date and time:
my %months = (Jan => 1, Feb => 2, Mar => 3, Apr => 4 ...);
my $st r= "Thu Mar 25 01:48:45 IST 2011";
$st =~! /\S+\s+(\S+)\s+(\S+)\s+\S+\s+\S+(\S+)/;
my $date = sprintf "%s-%02s-%02s", $3, $months{$1}, $2;
Okay, this is very error prone, and you probably want to do a lot of error checking. The regular expression I used could be formatted a bit stronger (checking for characters and numbers instead of just "not white space". And, you probably want to make sure the month is valid too.
Actually, you're better off using a Date/Time module to do this. I was going to recommend Time::Piece, but James_R_Ferguson beat me to it.

How do you read the system time and date in Perl?

I need to read the system clock (time and date) and display it in a human-readable format in Perl.
Currently, I'm using the following method (which I found here):
#!/usr/local/bin/perl
#months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
#weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print $theTime;
When you run the program, you should see a much more readable date and time like this:
9:14:42, Wed Dec 28, 2005
This seems like it's more for illustration than for actual production code. Is there a more canonical way?
Use localtime function:
In scalar context, localtime() returns
the ctime(3) value:
$now_string = localtime; # e.g., "Thu Oct 13 04:54:34 1994"
You can use localtime to get the time and the POSIX module's strftime to format it.
While it'd be nice to use Date::Format's and its strftime because it uses less overhead, the POSIX module is distributed with Perl, and is thus pretty much guaranteed to be on a given system.
use POSIX;
print POSIX::strftime( "%A, %B %d, %Y", localtime());
# Should print something like Wednesday, January 28, 2009
# ...if you're using an English locale, that is.
# Note that this and Date::Format's strftime are pretty much identical
As everyone else said "localtime" is how you tame date, in an easy and straight forward way.
But just to give you one more option. The DateTime module. This module has become a bit of a favorite of mine.
use DateTime;
my $dt = DateTime->now;
my $dow = $dt->day_name;
my $dom = $dt->mday;
my $month = $dt->month_abbr;
my $chr_era = $dt->year_with_christian_era;
print "Today is $dow, $month $dom $chr_era\n";
This would print "Today is Wednesday, Jan 28 2009AD". Just to show off a few of the many things it can do.
use DateTime;
print DateTime->now->ymd;
It prints out "2009-01-28"
Like someone else mentioned, you can use localtime, but I would parse it with Date::Format. It'll give you the timestamp formatted in pretty much any way you need it.
The simplest one-liner print statement to print localtime in clear, readable format is:
print scalar localtime (); #Output: Fri Nov 22 14:25:58 2019