File Coverage

blib/lib/Calendar/Any/Util/Lunar.pm
Criterion Covered Total %
statement 58 58 100.0
branch 4 6 66.6
condition 2 3 66.6
subroutine 6 6 100.0
pod 0 1 0.0
total 70 74 94.5


line stmt bran cond sub pod time code
1             package Calendar::Any::Util::Lunar;
2             {
3             $Calendar::Any::Util::Lunar::VERSION = '0.5';
4             }
5 2     2   26102 use Calendar::Any::Util::Solar;
  2         7  
  2         138  
6 2     2   12 use Calendar::Any::Gregorian;
  2         4  
  2         44  
7 2     2   10 use Math::Trig qw(deg2rad);
  2         3  
  2         174  
8 2     2   11 use POSIX qw/floor/;
  2         4  
  2         17  
9              
10             require Exporter;
11             our @ISA = qw(Exporter);
12             our %EXPORT_TAGS = ( 'all' => [ qw(
13             new_moon_date
14             ) ] );
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16              
17             #==========================================================
18             # Input : Calendar Object or absolute_date, timezone
19             # Output : *absolute date* that first new moon on or after
20             # input date
21             # Desc :
22             #==========================================================
23             sub new_moon_date {
24 2     2 0 8 my $d = shift;
25 2         3 my $tz = shift;
26 2         4 my $date;
27 2 100 66     20 if ( ref $d && ref $d eq 'Calendar::Any::Gregorian' ) {
28 1         2 $date = $d;
29             } else {
30 1 50       14 $date = Calendar::Any::Gregorian->new(ref $d ? $d->absolute_date : $d);
31             }
32 2         28 $d = $date->astro_date();
33 2         9 my $year = $date->year + $date->day_of_year / 365.25;
34 2         21 my $k = floor(($year-2000)*12.3685);
35 2         8 $date = _new_moon_time($k, $tz);
36 2         11 while ( $date <$d ) {
37 1         2 $k++;
38 1         2 $date = _new_moon_time($k, $tz);
39             }
40             # TODO: daylight time offset
41 2         15 return Calendar::Any->new_from_Astro($date)->absolute_date;
42             }
43              
44             sub _new_moon_time {
45 3     3   6 my $k = shift;
46 3         5 my $tz = shift;
47 3 50       8 defined($tz) || ($tz = $Calendar::Any::Util::Solar::timezone);
48 3         7 my $T = $k / 1236.85;
49 3         5 my $T2 = $T * $T;
50 3         5 my $T3 = $T2 * $T;
51 3         7 my $T4 = $T2 * $T2;
52 3         15 my $JDE = 2451550.09765 + 29.530588853*$k
53             + 0.0001337*$T2 - 0.000000150*$T3 + 0.00000000073*$T4;
54 3         6 my $E = 1 - 0.002516*$T - 0.0000074*$T2;
55 3         19 my $sun_anomaly = deg2rad(2.5534 + 29.10535669*$k - 0.0000218*$T2
56             - 0.00000011*$T3);
57 3         44 my $moon_anomaly = deg2rad(201.5643 +385.81693528*$k + 0.0107438*$T2
58             + 0.00001239*$T3 - 0.000000058*$T4);
59 3         29 my $moon_argument = deg2rad(160.7108 + 390.67050274*$k - 0.0016341*$T2
60             - 0.00000227*$T3 + 0.000000011*$T4);
61 3         26 my $omega = deg2rad(124.7746 - 1.56375580*$k + 0.0020691*$T2 + 0.00000215*$T3);
62 3         38 my $A1 = deg2rad(299.77 + 0.107408 * $k - 0.009173 * $T2);
63 3         24 my $A2 = deg2rad(251.88 + 0.016321 * $k);
64 3         23 my $A3 = deg2rad(251.83 + 26.641886 * $k);
65 3         25 my $A4 = deg2rad(349.42 + 36.412478 * $k);
66 3         29 my $A5 = deg2rad( 84.66 + 18.206239 * $k);
67 3         23 my $A6 = deg2rad(141.74 + 53.303771 * $k);
68 3         22 my $A7 = deg2rad(207.14 + 2.453732 * $k);
69 3         22 my $A8 = deg2rad(154.84 + 7.306860 * $k);
70 3         23 my $A9 = deg2rad( 34.52 + 27.261239 * $k);
71 3         22 my $A10 = deg2rad(207.19 + 0.121824 * $k);
72 3         23 my $A11 = deg2rad(291.34 + 1.844379 * $k);
73 3         37 my $A12 = deg2rad(161.72 + 24.198154 * $k);
74 3         22 my $A13 = deg2rad(239.56 + 25.513099 * $k);
75 3         28 my $A14 = deg2rad(331.55 + 3.592518 * $k);
76              
77 3         120 my $correction = -0.40720*sin($moon_anomaly)
78             + 0.17241 * $E *sin($sun_anomaly)
79             + 0.01608 * sin(2 * $moon_anomaly)
80             + 0.01039 * sin(2*$moon_argument)
81             + 0.00739 * $E * sin( $moon_anomaly - $sun_anomaly)
82             - 0.00514 * $E * sin($moon_anomaly + $sun_anomaly)
83             + 0.00208 * $E * $E * sin(2*$sun_anomaly)
84             - 0.00111 * sin($moon_anomaly - 2*$moon_argument)
85             - 0.00057 * sin($moon_anomaly + 2*$moon_argument)
86             + 0.00056 * $E * sin(2*$moon_anomaly+ $sun_anomaly)
87             - 0.00042 * sin(3*$moon_anomaly)
88             + 0.00042 * $E * sin($sun_anomaly+ 2* $moon_argument)
89             + 0.00038 * $E * sin($sun_anomaly - 2* $moon_argument)
90             - 0.00024 * $E * sin(2*$moon_anomaly - $sun_anomaly)
91             - 0.00017 * sin($omega)
92             - 0.00007 * sin($moon_anomaly + 2*$sun_anomaly)
93             + 0.00004 * sin(2*$moon_anomaly - 2*$moon_argument)
94             + 0.00004 * sin(3*$sun_anomaly)
95             + 0.00003 * sin($moon_anomaly+ $sun_anomaly -2 *$moon_argument)
96             + 0.00003 * sin(2*$moon_anomaly + 2* $moon_argument)
97             - 0.00003 * sin($moon_anomaly + $sun_anomaly + 2* $moon_argument)
98             + 0.00003 * sin($moon_anomaly - $sun_anomaly + 2*$moon_argument)
99             - 0.00002 * sin($moon_anomaly - $sun_anomaly - 2* $moon_argument)
100             - 0.00002 * sin(3*$moon_anomaly + $sun_anomaly)
101             + 0.00002 * sin(4*$moon_anomaly);
102              
103 3         26 my $additional = 0
104             + 0.000325 * sin($A1)
105             + 0.000165 * sin($A2)
106             + 0.000164 * sin($A3)
107             + 0.000126 * sin($A4)
108             + 0.000110 * sin($A5)
109             + 0.000062 * sin($A6)
110             + 0.000060 * sin($A7)
111             + 0.000056 * sin($A8)
112             + 0.000047 * sin($A9)
113             + 0.000042 * sin($A10)
114             + 0.000040 * sin($A11)
115             + 0.000037 * sin($A12)
116             + 0.000035 * sin($A13)
117             + 0.000023 * sin($A14);
118 3         10 my $newJDE = $JDE +$correction+$additional;
119 3         17 my $ec = Calendar::Any::Util::Solar::_ephemeris_correction(
120             Calendar::Any->new_from_Astro($newJDE)->to_Gregorian->year
121             );
122 3         29 return $newJDE - Calendar::Any::Util::Solar::_ephemeris_correction(
123             Calendar::Any->new_from_Astro($newJDE)->to_Gregorian->year
124             ) + $tz/60/24;
125             }
126              
127             1;
128              
129             __END__