Josh Laroche
Josh Laroche

Reputation: 11

Finding the time between two dates in 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?

Upvotes: 1

Views: 1888

Answers (3)

Sobrique
Sobrique

Reputation: 53508

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.

Upvotes: 3

newcoder
newcoder

Reputation: 492

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

Upvotes: 1

Borodin
Borodin

Reputation: 126772

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

Upvotes: 3

Related Questions