Finding the time between two dates in Perl - perl

I am trying to calculate and display, in minutes, the difference between the entered date and the present time. I have:
print "Enter a date YYYY MM DD. Remember perl's months go from 0-11.\n";
while ( #dateEnt < 1 ) {
my $dateEntered = <STDIN>;
chomp $dateEntered;
push #dateEnt, $dateEntered;
(#datedata) = split( /\s+/, $dateEntered );
$year = $datedata[0];
$month = $datedata[1];
$day = $datedata[2];
}
$time = time;
$readabletime = localtime($time);
use Time::Local;
$timeB = localtime [1];
$timeBetween = $readabletime[1] - $timeB;
print "The time between the dates is $timeBetween\n";
When I execute this, I get nothing for an answer. Any help?

Lets take a look at this last chunk
use Time::Local;
$timeB = localtime[1];
$timeBetween = $readabletime[1] - $timeB;
print "The time between the dates is $timeBetween\n";
The use statement is normally put at the top of the program because it's actually executed at compile time, but it's fine anywhere really
localtime[1] looks like you're trying to access the second element (Perl arrays start at index zero) of an array called localtime. But what you're actually doing is creating an anonymous array that contains the single value 1 and passing a reference to it to localtime. If you try print[1] instead, you'll see that you get something like ARRAY(0x22c4000). So localtime is trying to convert a memory address into a date and time
$readabletime[1] is attempting to access the second element of array #readabletime, which doesn't exists so it will evaluate to undef
You end up trying to subtract something like the string "Thu Mar 4 18:50:24 1971" from undef which is meaningless. I think you should get a fatal error something like
Argument "Thu Mar 4 18:50:24 1971" isn't numeric in subtraction

use strict; and use warnings; would have told you about a lot of the problems.
that while loop is redundant, because you push without any validation. So it'll always be true on the second iteration.
which makes #dateEnt redundant.
localtime in a scalar context gives a string. You cannot do maths with a string. (Occasionally you can cheat, because perl can convert it to a number, but that doesn't work with a date string).
use is usually at the top of a program, because it's the first thing 'done' regardless
localtime in an array context returns an array of values. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); you can do (localtime)[1] which gives you $min. But that's not too meaningful for comparing anyway.
$readabletime[1] refers to the second element of an array called #readabletime. This doesn't exist.
So to accomplish what you're after - I would suggest using Time::Piece (core perl module) like this:
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece
my $date;
while ( not $date ) {
print "Enter a date YYYY MM DD\n";
my $dateEntered = <STDIN>;
chomp $dateEntered;
$date = Time::Piece->strptime( $dateEntered, "%Y %m %d" );
}
print "Understood: $date\n";
my $timebetween_s = ( time() - $date->epoch );
print $timebetween_s, "s between then and now\n";
Note - it uses strptime to convert the entered date to a Time::Piece object (which you can just print if you want and get a stringified date, but you can also do other transformations). strptime supports lots of different formats.
But you just subtract $date->epoch - which gets the time in seconds since 1st Jan 1970, from time() which is also the time in seconds since 1st Jan 1970. This gives you a time delta like you want - in seconds. You'll need to divide it if you want different units.

you can try this
use strict;
use warnings;
use DateTime;
my $from_date = DateTime->new(
year => 2014,
month => 9,
day => 24,
hour => 9,
minute => 13,
second => 8,
time_zone => 'local',
);
print "$from_date\n";
my $current_date = DateTime->now( time_zone => 'local' )->set_time_zone('floating');
print "$current_date\n";
my $time_diff = $current_date - $from_date;
print 'year = ', $time_diff->years, "\n";
print 'month = ', $time_diff->months, "\n";
print 'days = ', $time_diff->days, "\n";
print 'hours = ', $time_diff->hours, "\n";
print 'minutes = ', $time_diff->minutes, "\n";
print 'secondss = ', $time_diff->seconds, "\n";
Result:
2014-09-24T09:13:08
2015-09-25T21:31:37
year = 1
month = 0
days = 1
hours = 12
minutes = 18
secondss = 29

Related

Getting garbage value while calculating difference between already defined and current time (perl script)

I have time (only in hours & minutes) defined in one text file and getting current time from machine. Below is my code and am getting garbage value as 3. Code in perl script. Data in text file is as:
##ID::name::time
228::one::18 30 30
97::two::20 30 00
Code is as : Please suggest.
my $timefromfile;
open(my $fh, "<", $paramfile) or die("Can't open $paramfile\n") ;
{
print "before while\n";
while (my $line = <$fh>) {
print "$line\n";
if($line !~ m/^\#/){
chomp($line);
#if line isn't blank, process it
if($line ne ""){
push(#all_linesSettings, $line);
my #lineseparator = split(/\::/, $line);
$timefromfile = $lineseparator[-1];
my $namefromfile = $lineseparator[-2];
my $IDfromfile = $lineseparator[-3];
print "File Time for $IDfromfile $namefromfile is
$timefromfile \n";
print "**********\n";
(my $sec,my $min,my $hour) = localtime();
printf("Current Time is in - HH:MM:SS format ");
#get time into a variable
my #t;
#t = ($hour, $min, $sec);
print "\n#t\n";
print "\n**********\n";
my $format = '%H %M %S';
my $diff = #t - Time::Piece->strptime($timefromfile, $format );
print "\n now slatime is $timefromfile\n";
print "difference in seconds $diff\n";
}
}
}
}
close $fh;
}
Step 1 of troubleshooting perl: Turn on use strict; and use warnings:
You try to parse $SLAtime but you don't ever define or declare it.
You declare $timefromfile but with no ; so that won't compile.
Your indentation is broken. (You've mismatched brackets).
You subtract a value from #t. That value is undefined because of the above and because you don't have strict or warnings just silently evaluates as zero. #t contains 3 elements, and that's how it's evaluated in a scalar context. That's probably where your 3 is coming from.
You have a printf mixed in there, with no format string or variable. Which is a bit weird.
It's unclear if you even load Time::Piece in the first place. Which makes it considerably harder to use.
Time::Piece->strptime uses the epoch as your baseline. You're comparing with 1st Jan 1970, so your delta will be much bigger than you think.
Something like:
#!/usr/bin/env perl
use strict;
use warnings;
use Time::Piece;
while (<DATA>) {
print;
unless (m/^\s*\#/) {
chomp;
my ( $ID, $name, $timestr ) = split /::/;
my $now = localtime;
#note - this assumes time stamps are from today, which may not be what you want.
my $converted_time = Time::Piece->strptime(
join( " ", $timestr, $now->year, $now->mon, $now->mday ),
'%H %M %S %Y %m %d' );
my $diff = $converted_time - $now;
print "Diff is: $diff s\n";
}
}
__DATA__
##ID::name::time
228::one::18 30 30
97::two::20 30 00
Gets you a bit closer.
my $diff = #t - Time::Piece->strptime($SLAtime, $format );
I'm guessing that you expect this to do a pairwise subtraction? (i.e., Subtract the first item in each list, then the second item, then the third item.)
It doesn't.
It evaluates each of the operands in scalar context, then subtracts those scalars. If one of the scalars is a string, it will first be coerced into a number.
When an array is evaluated in scalar context, the result is the number of items in the array.
So:
You start with #t - Time::Piece->strptime($SLAtime, $format )
#t is an array with three items in it and the strptime is a string looking something like "Sunday 3rd Nov, 1943" (the example from the Time::Piece docs; I don't know what your $format looks like), so the subtraction becomes 3 - "Sunday 3rd Nov, 1943"
"Sunday 3rd Nov, 1943" doesn't start with a digit, so its value as a number is 0, making your subtraction 3 - 0
Therefore, you always get 3 as the result.
If you want to subtract dates and/or times correctly, take a look at the DateTime module, which includes methods for performing date arithmetic.
You are trying to subtract a Time::Piece object from an array, which won't work.
You need to get the current time into a Time::Piece object too, and then subtracting them will return a Time::Seconds object, like this:
use Time::Piece;
use Time::Seconds;
my $current_time = Time::Piece->localtime();
my $timefromfile="2018-01-17 18 30 30";
my $format = "%Y-%m-%d %H %M %S";
my $diff = $current_time - Time::Piece->strptime($timefromfile, $format);
print "Difference in seconds is ", $diff->seconds(), "\n";
You'll also need to give the date to the strptime command. If you know the date is always today (and watch out for this around midnight) then you can simply do this:
my $timefromfile = $current_time->ymd() . " 18 30 30";
NOTE! I'm putting in the time from file as a hard-coded constant so the code above is runnable. You'll need to adapt accordingly.

How do calculate and convert localtime to unix time stamp in Perl

My script is :
use warnings;
use strict;
my $start_time = localtime();
$sql = "INSERT into Table1, Select (VAr1, Var2, Var3 ...........)";
my $end_time = localtime();
my $run_time = ($end_time - $start_time);
my #months = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
my ($sec, $min, $hour, $day,$month,$year) = (localtime($run_time))[0,1,2,3,4,5];
print "Unix time ".$run_time." converts to ".$months[$month]." ".$day.", ".($year +=1900);
print " ".$hour.":".$min.":".$sec."\n";
When I run it, I don't get the desire output.
Unix time 648 converts to Jan , 1900 ::
I need to get hour:min:sec
the time the script took to calculate the insert into the table.
Thank you
$run_time isn't a timestamp (a number of seconds since epoch representing a date-time), so it makes no sense to pass it to localtime.
my $s = $run_time % 60; $run_time = ($run_time - $s) / 60;
my $m = $run_time % 60; $run_time = ($run_time - $m) / 60;
my $h = $run_time;
my $formatted_run_time = sprintf "%d:%02d:%02d", $h, $m, $s;
You can get fancier too:
my $formatted_run_time =
$h ? sprintf "%d:%02d:%02d", $h, $m, $s
$m ? sprintf "%d:%02d", $m, $s
$s;
localtime is used to convert unix timestamps to a human-readable time (or a list of parts of it), but you are giving it a duration in seconds. It will treat it like a timestamp, and give you a very low date and time.
print scalar localtime 648;
# gives Thu Jan 1 01:10:48 1970
Your code gives the following output:
Unix time 648 converts to Jan 1, 1970 1:10:48
The problem is that you are essentially mixing two concepts here.
You might want to use the Benchmark module instead, which is intended for this exact purpose.
use strict;
use warning;
use Benchmark;
my $t0 = Benchmark->new;
# do your database stuff here
my $t1 = Benchmark->new;
my $td = timediff($t1, $t0);
print "the code took:",timestr($td),"\n";
If you are on a Linux or Unix, you can also use the time program to meassure the overall runtime of your program.
$ time perl foo.pl
real 0m2.241s
user 0m2.236s
sys 0m0.000s
$

get month year from a given date

I have a file that has a list of dates. I want to get the information of Month Year. I was doing the following: (I omit the part of open a file)
$request_date = "2012-01-02 08:12:11";
chomp(my $monthdatefile = `date '+%B %Y' --date='$request_date'`);
but it takes too much.
From Unix will be that what I want:
$ date '+%B %Y' --date='2012-01-02 08:12:11'
January 2012
Use Time::Piece like this
use strict;
use warnings;
use Time::Piece;
my $request_date = '2012-01-02 08:12:11';
my $tp = Time::Piece->strptime($request_date, '%Y-%m-%d %H:%M:%S');
my $month_year = $tp->strftime('%B %Y');
print $month_year;
output
January 2012
If you care about speed, I'd just have a hash table of 12 entries for months.
Then extract the fields as follows:
my %hash = (1 => 'January', 2=>'February', ...);
$request_date =~ /^(\d+)-(\d+)-/;
my ($year,$month) = ($1,$2);
print $hash{$month}." ".$year;

How to calculate the difference between two timestamp strings in Perl

I searched through all the possible questions but couldn't find the answer,
so can Perl experts help me on this one?
I have two timestamps like 05/25/2011 05:22:03 PM and 05/25/2011 05:34:08 PM. They are stored in string form.
my $str1 = '05/25/2011 05:22:03';
my $str2 = '05/25/2011 05:34:08';
The latter being the time of a job ending and former being the time it started.
How do I find out the difference in dates and time? The dates are the same in this case but they could differ as well.
I recommend that you use the Time::Piece module. It has been a core module since the release of version 9.5 of Perl 5, so it shouldn't need installing.
This code demonstrates
use strict;
use warnings;
use Time::Piece;
my $str1 = 'Execution started at 05/25/2011 05:22:03 PM';
my $str2 = 'Execution completed at 05/25/2011 05:34:08 PM';
my #times = map Time::Piece->strptime(/(\d.+M)/, '%m/%d/%Y %H:%M:%S %p'), $str1, $str2;
my $delta = $times[1] - $times[0];
print $delta->pretty;
output
12 minutes, 5 seconds
You can take advantage of DateTime and its subtract_datetime() method, which returns a DateTime::Duration object.
use Date::Parse;
use DateTime;
my $t1 = '05/25/2011 05:22:03';
my $t2 = '05/25/2011 05:34:08';
my $t1DateTime = DateTime->from_epoch( epoch => str2time( $t1 ) );
my $t2DateTime = DateTime->from_epoch( epoch => str2time( $t2 ) );
my $diff = $t2DateTime->subtract_datetime( $t1DateTime );
print "Diff in minutes: " . $diff->in_units('minutes') . "\n";
print "Diff in hours: " . $diff->in_units('hours') . "\n";
print "Diff in months: " . $diff->in_units('months') . "\n";

In Perl, how can I find last Thursday's date? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
In Perl, how can find the date of the previous Monday for a given date?
In the perl, how to write a function to get last Thursday's date? Today (11/21), I want to get 11/17. How can I figure out if a given date is a Sunday or not?
Seems like a work for DateTime (which is the module usually recommended to manipulate dates in Perl). This small example should answer both your questions:
use strict;
use warnings;
use DateTime;
my $d = DateTime->now;
while ( $d->day_of_week != 4 ) {
$d->subtract( days => 1 );
}
print $d->ymd;
Other posts use DateTime too, but they have issues this post addresses.
use DateTime qw( );
my $dt = DateTime->today( time_zone => 'local' );
$dt->subtract( days => ($dt->day_of_week - 4) % 7 );
say $dt->ymd(''); # 20111117
Issues addressed:
Uses the local date instead of the date in or near England.
Uses today instead of now since you're only dealing with dates.
Avoids needless loops.
Note:
Returns the current date is today is a Thursday. You accepted an answer that did the same, so I presume that's what you want.
Update: The above can fail on certain days for certain time zones. (Not all days have a midnight!) Solution:
use DateTime qw( );
my $dt = DateTime->now( time_zone => 'local' );
$dt->set_time_zone('floating');
$dt->truncate( to => 'days' );
$dt->subtract( days => ($dt->day_of_week - 4) % 7 );
say $dt->ymd(''); # 20111117
I'd use what larsen wrote, although reading the localtime reference won't hurt you. You could do something like this to check if its Sunday:
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset,
$dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
if ($dayOfWeek == 0) print("Don't go to work!");
If all you wanted to test was the day-of-the-week an array slice of the localtime() works nicely:
print q(Today is Sunday) if ((localtime)[6]==0)
You can also use Date::Calc:
How do I calculate the last and the next Saturday for any given date?
use Date::Calc qw( Today Day_of_Week Add_Delta_Days
Day_of_Week_to_Text Date_to_Text );
$searching_dow = 6; # 6 = Saturday
#today = Today();
$current_dow = Day_of_Week(#today);
if ($searching_dow == $current_dow)
{
#prev = Add_Delta_Days(#today,-7);
#next = Add_Delta_Days(#today,+7);
}
else
{
if ($searching_dow > $current_dow)
{
#next = Add_Delta_Days(#today,
$searching_dow - $current_dow);
#prev = Add_Delta_Days(#next,-7);
}
else
{
#prev = Add_Delta_Days(#today,
$searching_dow - $current_dow);
#next = Add_Delta_Days(#prev,+7);
}
}
$dow = Day_of_Week_to_Text($searching_dow);
print "Today is: ", ' ' x length($dow),
Date_to_Text(#today), "\n";
print "Last $dow was: ", Date_to_Text(#prev), "\n";
print "Next $dow will be: ", Date_to_Text(#next), "\n";
use Date::Calc qw(:all);
($week, $year) = Week_of_Year(Today());# Week_of_Year(2011,11,21);
print Date_to_Text(Add_Delta_Days(Monday_of_Week($week - 1,$year),3));#THU - MON = 3
#output:Thu 17-Nov-2011
#isSunday?
Day_of_Week(2011,11,20) == 7 # 7 is Sunday enum code(from 1 : Monday)
With just localtime and the POSIX base module, you can do this:
my #ltime = localtime();
my $t
= POSIX::mktime(( 0 ) x 3
, $ltime[3] - ( 7 - 4 + $ltime[6] )
, #ltime[4,5]
);
This will always give you the last Thursday before the last Sunday. So if the day is Saturday, it will give you the previous week's Thursday, but if it's Sunday, it will give you the last past Thursday.
If you prefer the last past Thursday computation, you might do this:
my $t
= POSIX::mktime(( 0 ) x 3
, $ltime[3] - $ltime[6] + ( $ltime[6] > 4 ? 4 : -3 )
, #ltime[4,5]
);
Date::Simple has a pretty clean interface.
#!/usr/bin/perl
use strict;
use warnings;
use Date::Simple qw/ today /;
my $d = today;
# If today is already Thurs, subtract 1 before searching for prior Thursday.
# If today is Thurs and you want to capture that (and not Thur a week ago),
# don't subtract the 1 from $d.
$d--;
$d-- while $d->day_of_week != 4;
print $d->strftime("%Y%m%d");