patternMinor
New Moon (not Twilight) Calculator
Viewed 0 times
newmoonnotcalculatortwilight
Problem
Photography is one of my hobbies, and, living in Canada, I have the possibility of seeing, and photographing, the Aurora Borealis (Northern Lights).
Now, these happen when there's ionization in the ionosphere typically resulting from strong solar winds which create a 'tear', resulting in the plasma visible as the 'Northern Lights'. The more intense the solar wind, the further south you can possibly see the 'tear'.
Since I live relatively far South in Canada, it will take a very strong solar event to cause the Northern lights to appear South of my position, so, it will inevitably be best seen looking North, when it happens.
Additionally, they are best seen when there are no clouds, and when the sky is as dark as possible.
Finally, the solar wind 'pushes' the Northern lights away from the sun, so they stretch further south on the 'dark' side of the earth, than the light side (they form an egg-shape, not a circle).
Due to the nature of the phenomenon, they can best be seen (for me):
I have written a system that checks various factors, and e-mails me when the conditions are good for viewing the Aurora. Hopefully, when all the celestial factors align, I will be able to wake up, get out, and take pictures of the majestic events....
The solar phase calculation is the part that is relevant to this question. I need to know how dark it is likely to be, and as a result, I need to know what phase the moon is in (and in a different process, when the moon rises and sets). If the moon is dark (new moon), then it is a good thing. The closer I am to new moon the better.
The following code is an implementation of the func
Now, these happen when there's ionization in the ionosphere typically resulting from strong solar winds which create a 'tear', resulting in the plasma visible as the 'Northern Lights'. The more intense the solar wind, the further south you can possibly see the 'tear'.
Since I live relatively far South in Canada, it will take a very strong solar event to cause the Northern lights to appear South of my position, so, it will inevitably be best seen looking North, when it happens.
Additionally, they are best seen when there are no clouds, and when the sky is as dark as possible.
Finally, the solar wind 'pushes' the Northern lights away from the sun, so they stretch further south on the 'dark' side of the earth, than the light side (they form an egg-shape, not a circle).
Due to the nature of the phenomenon, they can best be seen (for me):
- close to midnight (when my part of the world is furthest away from the sun - and the pointy-side of the egg-shaped aurora is closest to me)
- when there is no cloud cover
- when there is lots of solar activity (kp (a measure of solar activity) >= 8)
- I am in 'the country' to avoid light-pollution (instead of a city)
- there is no moon creating light.
I have written a system that checks various factors, and e-mails me when the conditions are good for viewing the Aurora. Hopefully, when all the celestial factors align, I will be able to wake up, get out, and take pictures of the majestic events....
The solar phase calculation is the part that is relevant to this question. I need to know how dark it is likely to be, and as a result, I need to know what phase the moon is in (and in a different process, when the moon rises and sets). If the moon is dark (new moon), then it is a good thing. The closer I am to new moon the better.
The following code is an implementation of the func
Solution
To accept user input for dates,
Perl has some features for writing numeric literals that you should take advantage of. Instead of
Considering that you only want an approximate answer, I am perplexed by your concern for tiny numbers. \$(102.026 \times 10^{-12}) \times N\$ amounts to slowdown of an additional 9 millionths of a second per month. The \$(235 \times 10^{-12}) \times N^2\$ term works out to 20 millionths of a second per month per month. At this rate, it would take millions of years before the time of the new moon is delayed by a whole night due to drag forces!
Once you drop the insignificant \$N^2\$ terms, the quadratic expressions become linear. You no longer need to loop (nor do you need to solve a quadratic equation).
To decide between the previous and the following month, just round off
DateTime::Format::Natural is a nice CPAN module to use. It spares you from having to input dates using the Unix epoch format and the tortured use of Perl-Bash-Perl to generate the table. (Defining a subroutine would also have helped you generate the whole table in Perl.)Perl has some features for writing numeric literals that you should take advantage of. Instead of
102.026 * 10**-12, you could write 102.026E-12. You can also insert underscores, as in 29.530_588_861. Constants would be better written asuse constant {
Y2K_EPOCH => 946_702_800,
Y2K_REF => 5.597_661,
LUNATION => 29.530_588_861,
K_FACTOR => 102.026E-12,
U_TO_S => 0.000_739,
UTK => 235E-12,
SECS_PER_DAY => 60 * 60 * 24,
};Considering that you only want an approximate answer, I am perplexed by your concern for tiny numbers. \$(102.026 \times 10^{-12}) \times N\$ amounts to slowdown of an additional 9 millionths of a second per month. The \$(235 \times 10^{-12}) \times N^2\$ term works out to 20 millionths of a second per month per month. At this rate, it would take millions of years before the time of the new moon is delayed by a whole night due to drag forces!
Once you drop the insignificant \$N^2\$ terms, the quadratic expressions become linear. You no longer need to loop (nor do you need to solve a quadratic equation).
$now is a misnomer, considering that the time can be overridden on the command line.To decide between the previous and the following month, just round off
$moons to the nearest integer.sub days_until_new_moon {
my $date = shift // time;
my $days = ($date - Y2K_EPOCH) / SECS_PER_DAY;
# Use sprintf() for rounding: http://stackoverflow.com/q/178539
my $moons = sprintf('%.0f', ($days - Y2K_REF) / LUNATION);
my $newmoon_days = Y2K_REF + LUNATION * $moons;
# Convert terrestrial time to universal time
$newmoon_days -= U_TO_S;
return $newmoon_days - $days;
}
say days_until_new_moon(@ARGV);Code Snippets
use constant {
Y2K_EPOCH => 946_702_800,
Y2K_REF => 5.597_661,
LUNATION => 29.530_588_861,
K_FACTOR => 102.026E-12,
U_TO_S => 0.000_739,
UTK => 235E-12,
SECS_PER_DAY => 60 * 60 * 24,
};sub days_until_new_moon {
my $date = shift // time;
my $days = ($date - Y2K_EPOCH) / SECS_PER_DAY;
# Use sprintf() for rounding: http://stackoverflow.com/q/178539
my $moons = sprintf('%.0f', ($days - Y2K_REF) / LUNATION);
my $newmoon_days = Y2K_REF + LUNATION * $moons;
# Convert terrestrial time to universal time
$newmoon_days -= U_TO_S;
return $newmoon_days - $days;
}
say days_until_new_moon(@ARGV);Context
StackExchange Code Review Q#73666, answer score: 6
Revisions (0)
No revisions yet.