Pathologically Eclectic Rubbish Lister PerlMonks

### day of year calculation

by lamp (Chaplain)
 on Feb 22, 2005 at 08:20 UTC Need Help??
lamp has asked for the wisdom of the Perl Monks concerning the following question:

I'm following no modules approach to find the day of year based on the user provided date.
```#!/usr/local/bin/perl
sub dayofyear {
(\$day1,\$month,\$year)=@_;
my(@d_in_m)=(0,31,28,31,30,31,30,31,31,30,31,30,31);
\$d_in_m[2]=29 if (&leap(\$year));
for(\$i=1;\$i<\$month;\$i++) {
\$k += \$d_in_m[\$i];
}
\$k += \$day1;
return \$k;
}
sub leap {
\$y = shift;
return 0 unless \$y % 4 == 0;
return 1 unless \$y % 100 == 0;
return 0 unless \$y % 400 == 0;
return 1;
}
print dayofyear(10,3,2005);
It's printing the correct value. Is there any way to optimize the above code / do it in a better way?

--Binoj

Replies are listed 'Best First'.
Re: calculate day of year
by Corion (Pope) on Feb 22, 2005 at 08:26 UTC

What's wrong with using localtime and Time::Local ?

```use strict;
use Time::Local;

sub dayofyear {
my (\$d,\$m,\$y) = @_;
\$m--;
(localtime(timelocal(0,0,0,\$d,\$m,\$y)))[7]
};

Beware of the behaviour of timelocal for years < 1000.

Re: day of year calculation
by reneeb (Chaplain) on Feb 22, 2005 at 11:48 UTC
You can also use Date::Calc:

```#! /usr/bin/perl

use strict;
use warnings;
use Date::Calc qw(Day_of_Year);

my \$doy = Day_of_Year(\$year,\$month,\$day);
print \$doy;
Re: day of year calculation
by betterworld (Curate) on Feb 22, 2005 at 11:56 UTC
Have you noticed that if you duplicate the last line (the line with "print"), you'll get two different results? First, it prints 69, which seems correct, but then it prints 138. This is because you don't use strict. Especially you should write "my \$k" to solve this issue.
Re: calculate day of year
by slayven (Pilgrim) on Feb 22, 2005 at 09:19 UTC
If you convert your date into seconds of the epoch you'll be able to feed it to localtime which, in list context, outputs the year of day as 7th index. Nevertheless, I don't think that it'll be easier to convert your date into seconds of the epoch without any Modules.

--
trust in bash
Re: day of year calculation
by mlh2003 (Scribe) on Feb 22, 2005 at 13:52 UTC
One way to speed things up a little is to get rid of the for loop by replacing the array containing the number of days in each month with the cumulative number of days. If the year is a leap year, add 1 to the result if the month is >2.

UPDATE (for explanation): In the code I check for the month > 1 since I subtract 1 from the month in the previous line.

```#!/usr/local/bin/perl

use strict;

sub dayofyear {
my (\$day1,\$month,\$year)=@_;
my @cumul_d_in_m=(0,31,59,90,120,151,181,212,243,273,304,334,365);
my \$doy=\$cumul_d_in_m[--\$month]+\$day1;
\$doy++ if (&leap(\$year) && \$month>1);
return \$doy;
}
sub leap {
my \$y = shift;
return 0 unless \$y % 4 == 0;
return 1 unless \$y % 100 == 0;
return 0 unless \$y % 400 == 0;
return 1;
}
print dayofyear(10,3,2005)."\n";
print dayofyear(10,3,2004)."\n";
print dayofyear(10,2,2005)."\n";
print dayofyear(10,2,2004)."\n";
This gives the following output:
69
70
41
41

1 less function call:

```#!/usr/local/bin/perl

use strict;

sub dayofyear {
my (\$day1,\$month,\$year)=@_;
my @cumul_d_in_m =
(0,31,59,90,120,151,181,212,243,273,304,334,365);
my \$doy=\$cumul_d_in_m[--\$month]+\$day1;
return \$doy if \$month < 2;
return \$doy unless \$year % 4 == 0;
return ++\$doy unless \$year % 100 == 0;
return \$doy unless \$year % 400 == 0;
return ++\$doy;
}

print dayofyear(10,3,2005)."\n";
print dayofyear(10,3,2004)."\n";
print dayofyear(10,2,2005)."\n";
print dayofyear(10,2,2004)."\n";

Create A New User
Node Status?
node history
Node Type: perlquestion [id://433280]
Approved by grinder
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2018-06-22 11:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Should cpanminus be part of the standard Perl release?

Results (124 votes). Check out past polls.

Notices?