Subject: | Astro::MoonPhase needs phaselist function |
I'm working on a module for creating calendars, and I want to include
the phase of the moon. Unfortunately, Astro::MoonPhase isn't very
helpful for this. The phasehunt function returns info for the current
lunar month, but that's not the same as a calendar month.
So, I implemented a phaselist function, which takes a start and stop
time and returns all the moon phases between them. I'm not an expert on
this, but I think it works correctly. I've attached a patch.
While I was at it, I removed the dependency on Time::Local, because you
weren't actually using timegm anymore.
I'd appreciate it if you could add phaselist to a new release of
Astro::MoonPhase.
Subject: | phaselist.patch |
--- MoonPhase.pm 2004-10-07 10:33:02.000000000 -0500
+++ MoonPhase.pm 2006-11-27 10:07:28.865884082 -0600
@@ -6,10 +6,8 @@
require Exporter;
@ISA = qw(Exporter);
-@EXPORT = qw(phase phasehunt);
-$VERSION = '0.52';
-
-use Time::Local qw(timegm);
+@EXPORT = qw(phase phasehunt phaselist);
+$VERSION = '0.60';
use vars qw (
$Epoch
@@ -288,6 +286,36 @@
}
+
+# phaselist - find time of phases of the moon between two dates
+# times (in & out) are seconds_since_1970
+
+sub phaselist
+{
+ my ($sdate, $edate) = map { jtime($_) } @_;
+
+ my (@phases, $d, $k, $yy, $mm);
+
+ jyear($sdate, \$yy, \$mm, \$d);
+ $k = floor(($yy + (($mm - 1) * (1.0 / 12.0)) - 1900) * 12.3685) - 2;
+
+ while (1) {
+ ++$k;
+ for my $phase (0.0, 0.25, 0.5, 0.75) {
+ $d = truephase($k, $phase);
+
+ return @phases if $d >= $edate;
+
+ if ($d >= $sdate) {
+ push @phases, int(4 * $phase) unless @phases;
+ push @phases, jdaytosecs($d);
+ } # end if date should be listed
+ } # end for each $phase
+ } # end while 1
+} # end phaselist
+
+
+
# kepler - solve the equation of Kepler
sub kepler {
@@ -458,6 +486,7 @@
@phases = phasehunt($seconds_since_1970);
+ ($phase, @times) = phaselist($start, $stop);
=head1 DESCRIPTION
@@ -577,6 +606,40 @@
Last quarter = Thu Jul 16 18:15:18 1998
New Moon = Thu Jul 23 16:45:01 1998
+=head2 phaselist()
+
+ ($phase, @times) = phaselist($start, $stop);
+
+Finds times of all phases of the moon which occur on or after
+C<$start> but before C<$stop>. Both the arguments and the return
+values are expressed as seconds since 1970 (like the C<time> function
+returns).
+
+C<$phase> is an integer indicating the phase of the moon at
+C<$times[0]>, as shown in this table:
+
+ 0 New Moon
+ 1 First quarter
+ 2 Full Moon
+ 3 Last quarter
+
+The remaining values in C<@times> indicate subsequent phases of the
+moon (in ascending order by time). If there are no phases of the moon
+between C<$start> and C<$stop>, C<phaselist> returns the empty list.
+
+Example:
+
+ @name = ("New Moon", "First quarter", "Full moon", "Last quarter");
+ ($phase, @times) = phaselist($start, $stop);
+
+ while (@times) {
+ printf "%-14s= %s\n", $name[$phase], scalar localtime shift @times;
+ $phase = ($phase + 1) % 4;
+ }
+
+could produce the same output as the C<phasehunt> example above (given
+the appropriate start & stop times).
+
=head1 ABOUT THE ALGORITHMS
The algorithms used in this program to calculate the positions of Sun and