Solved

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

Posted on 2004-09-19
13
674 Views
Last Modified: 2007-12-19
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.

0
Comment
Question by:divt
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 2
  • +2
13 Comments
 
LVL 18

Assisted Solution

by:kandura
kandura earned 140 total points
ID: 12095077
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
 
LVL 9

Expert Comment

by:ronan_40060
ID: 12095151
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
 
LVL 18

Expert Comment

by:kandura
ID: 12095191
"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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 9

Expert Comment

by:ronan_40060
ID: 12095230
thx kandura
excellent explanation
0
 
LVL 84

Expert Comment

by:ozo
ID: 12095549
return int($diff / 86400)
Could give the wrong answer if $d1 and $d2 cross a Daylight Saving Time transition.
0
 
LVL 18

Expert Comment

by:kandura
ID: 12095600
I'll leave that as an excercise for the reader ;)
0
 
LVL 18

Expert Comment

by:kandura
ID: 12095621
I'd like to see an example of that, ozo.
0
 
LVL 18

Expert Comment

by:kandura
ID: 12096392
   daydiff('27/3/2004', '29/3/2004') = 1

(I'm in CET)

ok. better use timegm instead of timelocal.
0
 
LVL 5

Accepted Solution

by:
ZiaTioN earned 180 total points
ID: 12097855
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
 
LVL 84

Assisted Solution

by:ozo
ozo earned 180 total points
ID: 12099625
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
 
LVL 5

Expert Comment

by:ZiaTioN
ID: 12102938
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
 
LVL 4

Author Comment

by:divt
ID: 12106570
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
 
LVL 84

Expert Comment

by:ozo
ID: 12107140
Julian Day Number
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
A year or so back I was asked to have a play with MongoDB; within half an hour I had downloaded (http://www.mongodb.org/downloads),  installed and started the daemon, and had a console window open. After an hour or two of playing at the command …
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans

634 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question