Solved

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

Posted on 2004-09-19
13
670 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
What is SQL Server and how does it work?

The purpose of this paper is to provide you background on SQL Server. It’s your self-study guide for learning fundamentals. It includes both the history of SQL and its technical basics. Concepts and definitions will form the solid foundation of your future DBA expertise.

 
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

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

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

Suggested Solutions

On Microsoft Windows, if  when you click or type the name of a .pl file, you get an error "is not recognized as an internal or external command, operable program or batch file", then this means you do not have the .pl file extension associated with …
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…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

770 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