go ahead... be a heretic PerlMonks

### Re: perl basic count days between two dates

by marinersk (Curate)
 on Oct 02, 2013 at 19:43 UTC ( #1056671=note: print w/replies, xml ) Need Help??

in reply to perl basic count days between two dates

There are modules that will do this for you. I acknowledge you indicate you do not wish to use a module.

So the first step is to figure out the algorithm you wish to use. Grab pencil and paper (or a whiteboard for you youngins), and start trying to figure out how you would do the math by hand.

Then try to write code that would do the same thing you did by hand.

The number of things you are likely to overlook or get wrong are controllable in this example, but high enough to reward your use of a Module where someone else (or several someone elses) took the time to iron out the bugs for you.

But if you just gotta write the code yourself, Step 1 is to figure out how to do it by hand.

P.S. I would suggest researching Leap Year Rules. Assuming your needs do not extend to earlier than Friday, October 15, 1582 in Catholic countries, 1698 or 1752 in principalities headed by Protestants, or 1918 in Russia, a shortcut to use only the modern computation should suffice.

In that computation, the base assumption is that every year has 365 days unless it is declared to be a leap year, in which case it has 366.

More specifically, February would have 29 days rather than the hard-coded 28 you presume in your code.

Research the Leap Year Rules, and you should be able to devise a subroutine which can determine if any given year is a leap year.

From there, you should have all the tools you need to compute number of days between dates, given sufficient forethought to the construction of either your computational algorithms, or your foreach loops -- or some combination thereof.

Update: Okay, fine, here's one example of the many things a module could do for you that you would have to grind through to do by hand:

```sub isLeapyear
{
my (\$year, @extraStuff) = @_;
if (!defined \$year) { \$year = 0; }

my \$leapYearFlag = 0;        # Assume not a leap year until proven
+ otherwise.

if (\$year % 4) {
# Not divisible by 4.  Cannot be a leap year.
\$leapYearFlag = 0;
} else {
# Divisible by 4.  Possibly a leap year.
if (\$year % 100) {
# Is not divisible by 100.  It is a leap year.
\$leapYearFlag = 1;
} else {
# Is divisible by 100.  May not be a leap year.
if (\$year % 400) {
# Is not divisible by 400.  Cannot be a leap year.
\$leapYearFlag = 0;
} else {
# Is divisible by 400.  IS a leap year.
\$leapYearFlag = 1;
}
}
}

return \$leapYearFlag;
}

Replies are listed 'Best First'.
Re^2: perl basic count days between two dates
by talexb (Canon) on Oct 03, 2013 at 21:04 UTC

There's always more than one way to do it .. I like to switch things around and test for the least likely outcome first .. check to see if the year is divisible by 400, then 100, and finally 4. I think it also makes the code a little more transparent, but everyone's got their own style ..

```#!/usr/bin/perl

use strict;
use warnings;

my %testData = (
1900 => 0,
1904 => 1,
1972 => 1,
1973 => 0,
1999 => 0,
2000 => 1,
2001 => 0,
2004 => 1
);

{
foreach my \$this ( keys %testData ) {

if ( \$testData{\$this} == leapYear(\$this) ) {

print "Correct - \$this year "
. ( \$testData{\$this} ? "is" : "is not" )
. " a leap year.\n";
}
else {

print "Error with \$this entry ..\n";
}
}
}

sub leapYear {

my \$year = shift;

if ( \$year % 400 ) {
if ( \$year % 100 ) {

#  3. Simple case: it's a leap year if it's divisible by 4
return ( \$year % 4 ) ? 0 : 1;
}
else {

#  2. If it's divisible by 100: it's not a leap year.
return 0;
}
}
else {

#  1. If it's divisible by 400: it's a leap year.
return 1;
}
}

I've numbered the comments to make it a little clearer which result might be returned first, although this could be made even clearer by reversing the meaning of the conditionals so that the routine looks like this:

```sub leapYear {

my \$year = shift;

if ( \$year % 400 == 0 ) {

#  1. If it's divisible by 400: it's a leap year.
return 1;
}
else {
if ( \$year % 100 == 0 ) {

#  2. If it's divisible by 100: it's not a leap year.
return 0;
}
else {

#  3. Simple case: it's a leap year if it's divisible by 4
return ( \$year % 4 ) ? 0 : 1;
}
}
}

Alex / talexb / Toronto

Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Create A New User
Node Status?
node history
Node Type: note [id://1056671]
help
Chatterbox?
 [ambrus]: Corion: ah, so you want a library that parses HTTP, and you want to do the IO yourself, and don't want a full AnyEvent wrapper. [ambrus]: Corion: I think I parsed a HTTP header from a string with LWP once. You can definitely use that to create a HTTP message too. The problme is [ambrus]: that if you do that, you'd have to find where each HTTP response ends, which is nontrivial if you want persistent connections (essential for performance if you have small requests). [Corion]: ambrus: Yes, ideally an API that I feed the incoming data piece by piece and that I can ask "is that response done" and "what should I do next" and "please construct the appropriate redirect for me" [Corion]: ambrus: Yes, ideally the module would do all that nasty stuff for me and give me a way to ask it what the current situation is [ambrus]: Corion: you could also consider using some wrapper over the multi interface of curl, I think Net::Curl might be a good one, since implementing enough of what it expects from the event loop might be easier than a full AnyEvent interface. [ambrus]: Corion: you could also consider using IO::Async and its POE driver and some HTTP module for it, but I don't know if that would solve your problems with AnyEvent+POE [ambrus]: Corion: wait, you didn't say POE. You said Prima, let me look up what that is.

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (16)
As of 2016-12-07 16:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
On a regular basis, I'm most likely to spy upon:

Results (130 votes). Check out past polls.