Solved

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

Posted on 2004-09-19
13
668 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
Comment Utility
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
Comment Utility
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
Comment Utility
"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
Comment Utility
thx kandura
excellent explanation
0
 
LVL 84

Expert Comment

by:ozo
Comment Utility
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
Comment Utility
I'll leave that as an excercise for the reader ;)
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 18

Expert Comment

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

Expert Comment

by:kandura
Comment Utility
   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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Julian Day Number
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
Checking the Alert Log in AWS RDS Oracle can be a pain through their user interface.  I made a script to download the Alert Log, look for errors, and email me the trace files.  In this article I'll describe what I did and share my script.
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…
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

772 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