Solved

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

Posted on 2004-09-19
13
669 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
  • 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
 
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

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…
In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
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…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …

911 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now