# calculate number of days between 2 dates (without external modules)

Problem illustration:
All inputs in format 'dd/mm/yyyy'

sample input A:
\$date1 = '21/10/2004';
\$date2 = '25/10/2004';

sample output A:
4

sample input B:
\$date1 = '21/10/2004';
\$date2 = '21/10/2005';

sample output B:
365

sample input C:
\$date1 = '21/10/2004';
\$date2 = '21/10/2020';

sample output C:
5844

Without using third party modules (Date::Calc etc.)
Must calculate correctly with leap years, etc.
Does this sound like reinventing the wheel?

Opinions welcome.

LVL 4
###### Who is Participating?

Commented:
Ok,

This should be what you are looking for! No Modules too.

#!/usr/bin/perl -w

use strict;

my \$sDate = '01/01/2004';
my \$eDate = '01/01/2020';

my @months = qw(Jan=31 Feb=28 Mar=31 Apr=30 May=31 Jun=30
Jul=31 Aug=31 Sep=30 Oct=31 Nov=30 Dec=31);

my (\$sMonth, \$sDay, \$sYear) = split(/\//, \$sDate);
my (\$eMonth, \$eDay, \$eYear) = split(/\//, \$eDate);
my (\$m, \$mTotal)            = split(/\=/, \$months[\$sMonth-1]);

my \$yRef = \$sYear;
my \$mRef = \$sMonth;
my \$i    = 0;

while (\$yRef <= \$eYear) {
my \$leap;
my \$lRef  = \$yRef / 4;
my \$lRef2 = \$yRef / 100;
my \$lRef3 = \$yRef / 400;

if (\$lRef !~ /\./) {
if ((\$lRef2 !~ /\./) && (\$lRef3 =~ /\./)) {
\$leap = 0;
}else{
\$leap = 1;
}
}else{
\$leap = 0;
}

if (\$yRef == \$eYear) {
while (\$mRef <= \$eMonth) {
\$mTotal = 29 if ((\$m eq "Feb") && (\$leap == 1));

if (\$mRef == \$eMonth) {
\$i++, \$sDay++, while(\$sDay < \$eDay);
}else{
\$i++, \$sDay++ while(\$sDay <= \$mTotal);
}

\$sDay = 1;
\$mRef++;
(\$m, \$mTotal) = split(/\=/, \$months[\$mRef-1]);
}
}else{
while (\$mRef < 12) {
\$mTotal = 29 if ((\$m eq "Feb") && (\$leap == 1));

\$i++, \$sDay++ while(\$sDay <= \$mTotal);
\$sDay = 1;
\$mRef++;
(\$m, \$mTotal) = split(/\=/, \$months[\$mRef-1]);
}
\$mRef = 0;
}
\$yRef++;
}
print "There are \$i days between \$sDate and \$eDate\n";
0

Commented:
Yes.

Would you object to using modules that are part of the perl distribution?

use Time::Local;
sub daydiff {
my (\$d1, \$d2) = @_;
my \$diff = date2time(\$d2) - date2time(\$d1);
return int(\$diff / 86400);
}

sub date2time {
my \$date = shift;
my (\$d, \$m, \$y) = split /\//, \$date;
return timelocal(0,0,0,\$d, \$m-1, \$y);
}
0

Commented:
Hello Kandura
I didnt not get the logic of  return timelocal(0,0,0,\$d, \$m-1, \$y);
cud u pls elaborate
thx
ronan
0

Commented:
"timelocal" is defined in Time::Local. It does the reverse of "localtime" in that it constructs a unix timestamp from date parts:

\$time = timelocal(\$sec,\$min,\$hour,\$mday,\$mon,\$year);

So timelocal(localtime(\$time)) == \$time.
0

Commented:
thx kandura
excellent explanation
0

Commented:
return int(\$diff / 86400)
Could give the wrong answer if \$d1 and \$d2 cross a Daylight Saving Time transition.
0

Commented:
I'll leave that as an excercise for the reader ;)
0

Commented:
I'd like to see an example of that, ozo.
0

Commented:
daydiff('27/3/2004', '29/3/2004') = 1

(I'm in CET)

ok. better use timegm instead of timelocal.
0

Commented:
Using timegm (or return sprintf"%.f",\$diff / 86400; with timelocal) seems the most sensible approach
but if you insist on using no modules at all, you could try:

sub JDN{
my(\$d,\$m,\$y)=\$_[0]=~/(\d\d)\D(\d\d)\D(\d\d\d\d)/ or die "bad date format";
if( \$m < 3 ){ \$m += 12; \$y -= 1; }
use integer;
return 1721088+\$d+(\$m-2)*367/12+\$y*365+\$y/4-\$y/100+\$y/400;
}
print JDN('21/10/2005')-JDN('21/10/2004'),"\n";
0

Commented:
I don't think he was looking for golfed but excellent obfuscated solution. I doubt most people will be able to even follow it but I enjoyed it! :-)
0

Author Commented:
Well, you may enjoy it, but I had a hard time digesting answers from you all experts! :-)

All answers yield the correct results for the illustratted problem.  Thank you for showing me the flexibility of perl.

By the way, Ozo, what does JDN stand for?

0

Commented:
Julian Day Number
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.