Ga Mmeeu
Ga Mmeeu

Reputation: 325

Perl: Calculate number of days by converting to seconds

I am trying to calculate the number of calendar days between two dates extracted from a database. I thought that converting the dates to seconds would be a simple and correct solution.

#!/usr/bin/perl
use warnings;
use strict;
use POSIX qw(strftime);
use Date::Parse;

my $minDate = "2016-03-27";
my $maxDate = "2016-06-15";

print "Format as extracted from db: mindate: $minDate and maxdate: $maxDate\n"; 

my ($dbYear,$dbMonth,$dbDay) = split ('-', $minDate);
my $datum = "$dbYear$dbMonth$dbDay";
my $minDateSec = str2time($datum);

($dbYear,$dbMonth,$dbDay) = split ('-', $maxDate);
$datum = "$dbYear$dbMonth$dbDay";
my $maxDateSec = str2time($datum);

my $numCalDaysSec = ($maxDateSec-$minDateSec)/86400;

print "Min date in Seconds: $minDateSec\n";
print "Max date in Seconds: $maxDateSec\n";
print "Num days: $numCalDaysSec\n";

Initially, I thought that this method provided me with reliable results:

bash-3.2$ ./testNumDays.pl
As extracted from db: mindate: 2016-06-14 and maxdate: 2016-06-15
Min date in Seconds: 1465855200
Max date in Seconds: 1465941600
Num days: 1
bash-3.2$ ./testNumDays.pl
As extracted from db: mindate: 2016-05-31 and maxdate: 2016-06-15
Min date in Seconds: 1464645600
Max date in Seconds: 1465941600
Num days: 15
bash-3.2$ ./testNumDays.pl
As extracted from db: mindate: 2016-03-28 and maxdate: 2016-06-15
Min date in Seconds: 1459116000
Max date in Seconds: 1465941600
Num days: 79
bash-3.2$ ./testNumDays.pl
As extracted from db: mindate: 2016-03-27 and maxdate: 2016-06-15
Min date in Seconds: 1459033200
Max date in Seconds: 1465941600
Num days: 79.9583333333333
bash-3.2$

Obviously, the number of calendar dates between dates should be an integer. Mmmm, what I am doing wrong? Why is converting to seconds not reliable?

Since I am a Perl newbie, I am probably overlooking the obvious. Any help is therefore more than welcome.

Upvotes: 6

Views: 704

Answers (3)

toolic
toolic

Reputation: 62236

One way is to use the Time::Piece Core module:

use warnings;
use strict;
use Time::Piece qw();

my $t1 = Time::Piece->strptime('2016-03-27', '%Y-%m-%d');
my $t2 = Time::Piece->strptime('2016-06-15', '%Y-%m-%d');
my $seconds = $t2 - $t1;
print $seconds->days(), "\n";

Output:

80

Upvotes: 7

hymie
hymie

Reputation: 2068

You are making the invalid assumption that every day is 86,400 seconds long.

Please go to http://www.timeanddate.com/time/dst/2016.html and look at all of the places where Daylight Saving Time (aka Summer Time) starts on 27 Mar 2016. That day is not 86,400 seconds long.

Upvotes: 3

simbabque
simbabque

Reputation: 54381

An alternative is DateTime. It's not in Core, but it's often very handy. Because it doesn't parse dates, we quickly made our own parsing function.

use strict;
use warnings;
use DateTime;
my $minDate = "2016-03-27";
my $maxDate = "2016-06-15";

sub parse {
    my $date = shift;

    my ( $y, $m, $d ) = split /-/, $date;

    return DateTime->new( year => $y, month => $m, day => $d );
}

my $days = parse($minDate)->delta_days(parse($maxDate))->in_units('days');
print $days;

__END__

80

Upvotes: 5

Related Questions