File Coverage

blib/lib/Date/Indian.pm
Criterion Covered Total %
statement 73 550 13.2
branch 5 118 4.2
condition 1 40 2.5
subroutine 16 67 23.8
pod 1 24 4.1
total 96 799 12.0


line stmt bran cond sub pod time code
1            
2             # ======================================================================
3             # U t i l i t y f u n c t i o n s
4             # These are functions that may be used by other local modules.
5             package Util;
6 1     1   8440 use Math::Trig;
  1         38303  
  1         211  
7            
8 1     1   12 use Exporter;
  1         3  
  1         84  
9             our @ISA = qw(Exporter);
10             our @EXPORT = qw(circle radians frac);
11            
12             my $PI = 4.0 * atan2(1.0,1.0);
13 1     1   6 use strict;
  1         7  
  1         247  
14            
15             # Rationalize the argument in gegrees into range 0...360.
16             sub circle{
17 0     0   0 my $angle = shift;
18 0         0 $angle = $angle - int($angle/360)*360;
19 0 0       0 if ($angle < 0.0) {$angle += 360.0;}
  0         0  
20 0         0 return $angle;
21             }
22            
23             # convert degrees to radians, rationalizing as needed.
24             sub radians{
25 0     0   0 my $angle = shift;
26 0         0 $angle = $angle - int($angle/360)*360;
27 0 0       0 if ($angle < 0.0) {$angle += 360.0;}
  0         0  
28 0         0 return $angle * $PI/180.0;
29             }
30            
31             # what does it do exactly?
32             sub frac{
33 0     0   0 my $x = shift;
34 0         0 my $a;
35 0         0 $a = $x - int($x);
36 0 0       0 $a += 1 if ($a < 0);
37 0         0 return $a;
38             }
39            
40             1;
41             # ======================================================================
42             # B a s e c l a s s f o r L u m i n i r i e s
43             package Luminary;
44 1     1   7 use strict;
  1         2  
  1         1155  
45 0     0   0 sub circle{return Util::circle(@_)};
46             #my $PI = 4.0 * atan2(1.0,1.0);
47             my $rad = $PI/180.0;
48             sub new{
49 0     0   0 my $proto = shift;
50 0   0     0 my $class = ref($proto) || $proto;
51 0         0 my $self = { @_ };
52 0         0 bless $self, $class;
53 0         0 return $self;
54             }
55             sub sinalt{
56 0     0   0 my $self = shift;
57 0   0     0 my $dayid = shift || 0;
58 0         0 my $hour = shift;
59 0         0 my $d = $self->{jdate} -2451545 +$dayid;
60 0         0 my $t = ($d + $hour/24.0 - $self->{tzone}/24.0 )/36525.0;
61 0         0 $d = $t * 36525.0;
62 0         0 my ($ra,$dec) = $self->radec($t);
63 0         0 my $lmst = circle(280.46061837 + 360.98564736629* $d +
64             0.000387933 *$t*$t - $t*$t*$t / 38710000)/15.0 +
65             $self->{longitude}/15.0;
66 0         0 my $tau = 15.0 * ($lmst - $ra);
67 0         0 return sin($rad*$self->{latitude}) * sin($rad*$dec) +
68             cos($rad*$self->{latitude}) * cos($rad*$dec) *
69             cos($rad * $tau);
70             }
71             sub riseset{
72 0     0   0 my $self = shift;
73 0   0     0 my $dayid = shift || 0;
74 0         0 my $above = undef;
75 0         0 my $hour = 1.0;
76 0         0 my $utrise = undef;
77 0         0 my $utset = undef;
78 0         0 my $rads = 0.0174532925;
79 0         0 my $sinho = $self->sinho(); #sin($rads * -0.833);
80 0         0 my $ym = $self->sinalt($dayid,$hour - 1.0) - $sinho;
81 0 0       0 $above = 'always above' if ($ym > 0.0);
82 0   0     0 while($hour < 25 && (not defined($utset) or not defined($utrise))) {
      0        
83 0         0 my $yz = $self->sinalt($dayid,$hour) - $sinho;
84 0         0 my $yp = $self->sinalt($dayid,$hour + 1.0) - $sinho;
85 0         0 my ($nz, $z1, $z2, $xe, $ye) = quad($ym, $yz, $yp);
86             # case when one event is found in the interval
87 0 0       0 if ($nz == 1) {
88 0 0       0 if ($ym < 0.0) { $utrise = $hour + $z1; }
  0         0  
89 0         0 else { $utset = $hour + $z1; }
90             } # end of nz = 1 case
91             # case where two events are found in this interval
92             # (rare but whole reason we are not using simple iteration)
93 0 0       0 if ($nz == 2) {
94 0 0       0 if ($ye < 0.0) {
95 0         0 $utrise = $hour + $z2; $utset = $hour + $z1;
  0         0  
96             }else{
97 0         0 $utrise = $hour + $z1; $utset = $hour + $z2;
  0         0  
98             }
99             }
100             # set up the next search interval
101 0         0 $ym = $yp;
102 0         0 $hour += 2.0;
103             } # end of while loop
104 0         0 return ($utrise,$utset,$above);
105             }
106             # quad finds the parabola throuh the three points (-1,ym), (0,yz), (1, yp)
107             # and returns the coordinates of the max/min (if any) xe, ye
108             # the values of x where the parabola crosses zero (roots of the quadratic)
109             # and the number of roots (0, 1 or 2) within the interval [-1, 1]
110             # results passed as array [nz, z1, z2, xe, ye]
111             sub quad{
112 0     0   0 my $ym = shift;
113 0         0 my $yz = shift;
114 0         0 my $yp = shift;
115 0         0 my $nz = 0;
116 0         0 my $a = 0.5 * ($ym + $yp) - $yz;
117 0         0 my $b = 0.5 * ($yp - $ym);
118 0         0 my $c = $yz;
119 0         0 my $xe = -$b / (2 * $a);
120 0         0 my $ye = ($a * $xe + $b) * $xe + $c;
121 0         0 my $dis = $b * $b - 4.0 * $a * $c;
122 0         0 my ($z1,$z2);
123 0 0       0 if ($dis > 0){
124 0         0 my $dx = 0.5 * sqrt($dis) / abs($a);
125 0         0 $z1 = $xe - $dx;
126 0         0 $z2 = $xe + $dx;
127 0 0       0 if (abs($z1) <= 1.0) {$nz += 1;}
  0         0  
128 0 0       0 if (abs($z2) <= 1.0) {$nz += 1;}
  0         0  
129 0 0       0 if ($z1 < -1.0) {$z1 = $z2;}
  0         0  
130             }
131 0         0 return ($nz,$z1,$z2,$xe,$ye);
132             }
133             sub ayanamsa{
134             # Source: http://www.jyotishtools.com/JScripts/bhavcalc.htm
135             #Calculate the Lahiri Ayanamsa by using
136             #Erlewine Fagan-Bradley sidereal calculation
137             # with correction using Lahiri 1900 value in minutes (see below)
138             # Correct jd with hr and tz values and reduce to fract of centuries.
139 0     0   0 my $self = shift;
140 0         0 my $d2r = 0.0174532925;
141 0         0 my $t = (($self->{jdate} - 2415020) - 0.5)/36525;
142 0         0 my $ln = ((933060-6962911*$t+7.5*$t*$t)/3600.0) % 360.0; # Mean lunar node
143 0         0 my $off = (259205536.0*$t+2013816.0)/3600.0; # Mean Sun
144 0         0 $off = 17.23*sin($d2r * $ln)+1.27*sin($d2r * $off)-(5025.64+1.11*$t)*$t;
145 0         0 $off = ($off- 80861.27)/3600.0; # 84038.27 = Fagan-Bradley 80861.27 = Lahiri
146 0         0 return $off;
147             }
148             sub longitude{
149 0     0   0 my $self = shift;
150 0   0     0 my $time = shift || 0.0;
151 0 0       0 $self->setLongitude($time) unless exists $self->{gclong};
152 0         0 return $self ->{gclong};
153             }
154            
155             # Nirayana longitude.
156             sub n_long{
157 0     0   0 my $self = shift;
158 0   0     0 my $time = shift || 0.0;
159 0         0 my $t = $self->longitude($time) + $self->ayanamsa();
160 0 0       0 $t += 360.0 if $t < 0.0;
161 0         0 return $t;
162             }
163             1;
164             # ======================================================================
165            
166            
167            
168             # ======================================================================
169             # T h e S u n O b j e c t
170             package Sun;
171 1     1   7 use strict;
  1         2  
  1         146  
172             our @ISA = qw (Luminary);
173 1     1   7 use Math::Trig;
  1         1  
  1         231  
174 1     1   6 use constant PI => 4.0 * atan2(1.0,1.0);
  1         2  
  1         1158  
175 0     0   0 sub circle{return Util::circle(@_)};
176 0     0   0 sub radians{return Util::radians(@_)};
177 0     0   0 sub frac{return Util::frac(@_)};
178            
179             sub setLongitude{
180 0     0   0 my $self = shift;
181 0         0 my $time = shift;
182 0         0 my $t = ($self->{jdate} -2415020 +$time -$self->{tzone}/24.0) / 36525.0;
183 0         0 my $dn = $t * 36525.0;
184 0         0 my $t2 = $t*$t;
185 0         0 my $t3 = $t2* $t;
186 0         0 my $mnln = radians ( 279.69668 + $t * 36000.76892 + $t2 * 0.0003025 );
187 0         0 my $ecc = 0.01675104 - $t * 0.0000418 - $t2 * 0.000000126;
188 0         0 my $orbr = 1.0000002;
189 0         0 my $anom = radians(358.475833+35999.04975*$t -1.50e-4*$t*$t -3.3e-6*$t*$t*$t);
190 0         0 my $anmn = $anom;
191 0         0 my $daily = radians(1.0);
192 0         0 my $a = radians ( 153.23 + 22518.7541 * $t );
193 0         0 my $b = radians ( 216.57 + 45037.5082 * $t );
194 0         0 my $c = radians ( 312.69 + 32964.3577 * $t );
195 0         0 my $d = radians ( 350.74 + 445267.1142 * $t - 0.00144 * $t2 );
196 0         0 my $e = radians ( 231.19 + 20.20 * $t );
197 0         0 my $h = radians ( 353.40 + 65928.7155 * $t );
198 0         0 my $c1 = radians (( 1.34 * cos ( $a ) + 1.54 * cos ( $b )
199             + 2.0 * cos ( $c ) + 1.79 * sin ( $d )
200             + 1.78 * sin ( $e ) ) * 1.00e-3);
201 0         0 my $c2 = radians(( 0.543 *sin ( $a ) + 1.575*sin ( $b )
202             + 1.627 *sin ( $c ) + 3.076 * cos ( $d )
203             + 0.927 *sin ( $h ) ) * 1.0e-5 );
204 0         0 my $incl = 0.0;
205 0         0 my $ascn = 0.0;
206 0         0 my $anec = 0.0;
207             #incl *= PiBy180 ;
208             #ascn *= PiBy180 ;
209            
210 0         0 for( my$eold = $anmn; abs( $anec -$eold ) > 1.0e-8; $eold = $anec){
211 0         0 $anec = $eold + ( $anmn + $ecc * sin( $eold ) - $eold )
212             / ( 1.0 - $ecc * cos ( $eold ) );
213             }
214 0         0 my $antr = atan ( sqrt ( (1.0 + $ecc ) / ( 1.0 - $ecc ) )
215             * tan ( $anec / 2.0 ) ) * 2.0 ;
216 0 0       0 $antr += 2.0*PI if ( $antr < 0.0 ) ;
217            
218             # calculate the helio centric longitude trlong.
219 0         0 my $u = $mnln + $antr - $anmn - $ascn ;
220 0 0       0 $u -= 2.0*PI if ( $u > 2.0*PI ) ;
221 0 0       0 $u += 2.0*PI if ( $u < 0.0 ) ;
222 0         0 my $n = int( $u *2.0 / PI );
223 0         0 my $uu = atan ( cos ( $incl ) * tan ( $u ) ) ;
224 0 0       0 $uu += PI if $n != int ( $uu *2.0/ PI ) ;
225 0 0       0 $uu += PI if ( $n == 3 ) ;
226 0         0 my $trlong = $uu + $ascn + $c1;
227 0         0 my $rad = $orbr * ( 1.0 - $ecc * cos ( $anec ) ) + $c2;
228             #my $erad = $rad;
229             #my $elong = $trlong;
230 0         0 $self->{gclong} = circle($trlong * 180.0 / PI);
231 0         0 return $self->{gclong};
232             }
233             sub sinho{
234 0     0   0 my $rads = 0.0174532925;
235 0         0 my $sinho = sin($rads * -0.833);
236             }
237             sub radec{
238 0     0   0 my $self = shift;
239 0         0 my $t = shift; #($self->{jdate} -2451544.5)/36524.0;
240 0         0 my $p2 = 6.283185307;
241 0         0 my $arc = 206264.8062;
242 0         0 my $coseps = 0.91748;
243 0         0 my $sineps = 0.39778;
244 0         0 my $M = $p2 * frac(0.993133 + 99.997361 * $t);
245 0         0 my $DL = 6893.0 * sin($M) + 72.0 * sin(2 * $M);
246 0         0 my $L = $p2 * frac(0.7859453 + $M / $p2 + (6191.2 * $t + $DL)/1296000);
247 0         0 my $SL = sin($L);
248 0         0 my $X = cos($L);
249 0         0 my $Y = $coseps * $SL;
250 0         0 my $Z = $sineps * $SL;
251 0         0 my $RHO = sqrt(1 - $Z * $Z);
252 0         0 my $dec = (360.0 / $p2) * atan($Z / $RHO);
253 0         0 my $ra = (48.0 / $p2) * atan($Y / ($X + $RHO));
254 0 0       0 $ra += 24 if ($ra <0 );
255 0         0 return ($ra,$dec);
256             }
257             1;
258            
259             # ======================================================================
260            
261            
262             # ======================================================================
263             # T h e M o o n O b j e c t
264            
265             package Moon;
266 1     1   6 use strict;
  1         2  
  1         27  
267 1     1   5 use Math::Trig;
  1         1  
  1         1620  
268             our @ISA = qw (Luminary);
269 0     0   0 sub circle{return Util::circle(@_)};
270 0     0   0 sub radians{return Util::radians(@_)};
271 0     0   0 sub frac{return Util::frac(@_)};
272            
273             sub setLongitude {
274 0     0   0 my $self = shift;
275 0         0 my $time = shift;
276             #my $t = ($self->{jdate} -2415020 + $self->{time}) / 36525.0;
277 0         0 my $t = ($self->{jdate} -2415020 +$time -$self->{tzone}/24.0) / 36525.0;
278 0         0 my $dn = $t * 36525.0;
279 0         0 my ($A,$B,$C,$D,$E,$F, $l, $M, $mm);
280 0         0 my $t2 = $t*$t;
281 0         0 my $t3 = $t2* $t;
282 0         0 my ($ang,$ang1);
283 0         0 my $anom = circle(358.475833+35999.04975*$t -1.50e-4*$t2 -3.3e-6*$t3);
284 0         0 $A = 0.003964 * sin ( radians( 346.56 +
285             $t * 132.87 - $t2 * 0.0091731) );
286 0         0 $B = sin ( radians( 51.2 + 20.2 * $t ) );
287 0         0 my $omeg = circle ( 259.183275 - 1934.1420 * $t
288             + 0.002078 * $t2 + 0.0000022 * $t3 );
289 0         0 $C = sin ( radians($omeg) );
290            
291 0         0 $l = circle ( 270.434164 + 481267.8831 * $t - 0.001133 * $t2 + 0.0000019 * $t3 + 0.000233 * $B + $A + 0.001964 * $C );
292 0         0 $mm = radians ( 296.104608 + 477198.8491 * $t + 0.009192 * $t2 + 1.44e-5 * $t3 + 0.000817 * $B + $A + 0.002541 * $C );
293 0         0 $D = radians ( 350.737486 + 445267.1142 * $t - 0.001436 * $t2 + 1.9e-6 * $t3 + $A + 0.002011 * $B + 0.001964 * $C );
294 0         0 $F = radians ( 11.250889 + 483202.0251 * $t - 0.003211 * $t2 - 0.0000003 * $t3 + $A - 0.024691 * $C
295             - 0.004328 * sin ( radians ( $omeg + 275.05 - 2.3 * $t ) ) ) ;
296 0         0 $M = radians( $anom - 0.001778 * $B );
297 0         0 $E = 1.0 - 0.002495 * $t - 0.00000752 * $t2;
298 0         0 $ang = $l
299             + 6.288750 * sin ( $mm )
300             + 1.274018 * sin ( $D + $D - $mm )
301             + 0.658309 * sin ( $D + $D )
302             + 0.213616 * sin ( $mm + $mm )
303             - 0.114336 * sin ( $F + $F )
304             + 0.058793 * sin ( $D + $D -$mm -$mm );
305 0         0 $ang = $ang + 0.053320 * sin ( $D + $D + $mm )
306             - 0.034718 * sin ( $D )
307             + 0.015326 * sin ( $D + $D - $F - $F )
308             - 0.012528 * sin ( $F + $F + $mm )
309             - 0.010980 * sin ( $F + $F -$mm );
310 0         0 $ang = $ang + 0.010674 * sin ( 4.0 * $D - $mm )
311             + 0.010034 * sin ( 3.0 * $mm )
312             + 0.008548 * sin ( 4.0 * $D -$mm -$mm )
313             + 0.005162 * sin ( $mm -$D )
314             + 0.003996 * sin ( $mm + $mm +$D + $D )
315             + 0.003862 * sin ( 4.0 * $D );
316 0         0 $ang = $ang + 0.003665 * sin ( $D +$D - $mm -$mm - $mm )
317             + 0.002602 * sin ( $mm - $F - $F - $D - $D )
318             - 0.002349 * sin ( $mm + $D )
319             - 0.001773 * sin ( $mm +$D + $D -$F - $F )
320             - 0.001595 * sin ( $F + $F + $D + $D )
321             - 0.001110 * sin ( $mm + $mm + $F + $F );
322 0         0 $ang1 = -0.185596 * sin ( $M )
323             + 0.057212 * sin ( $D + $D - $M - $mm )
324             + 0.045874 * sin ( $D + $D - $M )
325             + 0.041024 * sin ( $mm - $M )
326             - 0.030465 * sin ( $mm + $M )
327             - 0.007910 * sin ( $M - $mm + $D + $D )
328             - 0.006783 * sin ( $D + $D + $M )
329             + 0.005000 * sin ( $M + $D );
330 0         0 $ang1 = $ang1 + 0.004049 * sin ( $D +$D + $mm - $M )
331             + 0.002695 * sin ( $mm + $mm - $M )
332             + 0.002396 * sin ( $D + $D - $M - $mm - $mm )
333             - 0.002125 * sin ( $mm + $mm + $M )
334             + 0.001220 * sin ( 4.0 * $D - $M - $mm );
335 0         0 $ang1 = $ang1 + $E * (
336             0.002249 * sin ( $D + $D - $M - $M )
337             - 0.002079 * sin ( $M + $M )
338             + 0.002059 * sin ( $D + $D - $M - $M -$mm )
339             );
340            
341 0         0 $self->{gclong} = circle ($ang + $E * $ang1);
342             }
343             sub sinho{
344 0     0   0 my $rads = 0.0174532925;
345 0         0 my $sinho = sin($rads * 8.0/60.0);
346             }
347            
348             sub radec{
349             # takes t and returns the geocentric ra and dec in an array mooneq
350             # claimed good to 5' (angle) in ra and 1' in dec
351             # tallies with another approximate method and with ICE for a couple of dates
352 0     0   0 my $self = shift;
353 0         0 my $t = shift;
354 0         0 my $p2 = 6.283185307;
355 0         0 my $arc = 206264.8062;
356 0         0 my $coseps = 0.91748;
357 0         0 my $sineps = 0.39778;
358 0         0 my $L0 = frac(0.606433 + 1336.855225 * $t); # mean longitude of moon
359 0         0 my $L = $p2 * frac(0.374897 + 1325.552410 * $t); #mean anomaly of Moon
360 0         0 my $LS = $p2 * frac(0.993133 + 99.997361 * $t); #mean anomaly of Sun
361 0         0 my $D = $p2 * frac(0.827361 + 1236.853086 * $t); #diff in longitude of moon and sun
362 0         0 my $F = $p2 * frac(0.259086 + 1342.227825 * $t); #mean argument of latitude
363            
364             # corrections to mean longitude in arcsec
365 0         0 my $DL = 22640 * sin($L) -4586 * sin($L - 2*$D) +2370 * sin(2*$D);
366 0         0 $DL += +769 * sin(2*$L) -668 * sin($LS) -412 * sin(2*$F);
367 0         0 $DL += -212 * sin(2*$L - 2*$D) -206 * sin($L + $LS - 2*$D);
368 0         0 $DL += +192 * sin($L + 2*$D) -165 * sin($LS - 2*$D);
369 0         0 $DL += -125 * sin($D) -110 * sin($L + $LS) +148 * sin($L - $LS);
370 0         0 $DL += -55 * sin(2*$F - 2*$D);
371            
372             # simplified form of the latitude terms
373 0         0 my $S = $F + ($DL + 412 * sin(2*$F) + 541* sin($LS)) / $arc;
374 0         0 my $H = $F - 2*$D;
375 0         0 my $N = -526 * sin($H)+44 * sin($L + $H) -31 * sin(-$L + $H);
376 0         0 $N += -23 * sin($LS + $H) +11 * sin(-$LS + $H) -25 * sin(-2*$L + $F);
377 0         0 $N += +21 * sin(-$L + $F);
378            
379             # ecliptic long and lat of Moon in rads
380 0         0 my $L_moon = $p2 * frac($L0 + $DL / 1296000);
381 0         0 my $B_moon = (18520.0 * sin($S) + $N) /$arc;
382            
383             # equatorial coord conversion - note fixed obliquity
384 0         0 my $CB = cos($B_moon);
385 0         0 my $X = $CB * cos($L_moon);
386 0         0 my $V = $CB * sin($L_moon);
387 0         0 my $W = sin($B_moon);
388 0         0 my $Y = $coseps * $V - $sineps * $W;
389 0         0 my $Z = $sineps * $V + $coseps * $W;
390 0         0 my $RHO = sqrt(1.0 - $Z*$Z);
391 0         0 my $dec = (360.0 / $p2) * atan($Z / $RHO);
392 0         0 my $ra = (48.0 / $p2) * atan($Y / ($X + $RHO));
393 0 0       0 $ra += 24 if ($ra <0 );
394 0         0 return ($ra,$dec);
395             }
396             1;
397             # ======================================================================
398            
399            
400             # ======================================================================
401             # T h e I n d i a n D a t e O b j e c t
402             package Date::Indian;
403 1     1   8 use strict;
  1         1  
  1         61  
404             our @ISA = qw (Util);
405             our $VERSION = '0.01';
406 1     1   6430 use Math::Trig;
  1         5  
  1         4410  
407            
408             #sub circle{return Util::circle(@_)};
409             #sub radians{return Util::radians(@_)};
410             #sub sind{return Util::sind(@_)};
411             #sub cosd{return Util::cosd(@_)};
412             #sub asind{return Util::asind(@_)};
413             #sub acosd{return Util::acosd(@_)};
414             #sub angle{return Util::angle(@_)};
415            
416             sub new{
417 1     1 0 22 my $proto = shift;
418 1   33     7 my $class = ref($proto) || $proto;
419 1         7 my $self = {
420             ymd => undef, # ex: ymd => '2003-10-31'
421             tz => undef, # ex: tz => '-5:30'
422             locn => undef, # ex: locn =>'82:30E 17:25N'
423             jdate => undef, # ex: jdate => 2452850.93055556 (2003-7-30 10:20hrs)
424             @_
425             };
426 1         2 bless $self, $class;
427 1         5 $self->_dotz(); $self->_dolocn();
  1         4  
428 1 50       21 if ($self->{jdate}){
429 0         0 $self->_getdatetime();
430             }else{
431 1         16 $self->_doymd();
432             }
433             #$self->_getdatetime();
434 1         3 return $self;
435             }
436            
437             sub _doymd{
438 1     1   22 my $self = shift;
439 1         6 my ($y,$m,$d) = split(/-/,$self->{ymd});
440 1         3 $self -> {year} = $y; $self->{month} = $m; $self->{day} = $d;
  1         2  
  1         3  
441 1         3 $self->{jdate} = $self->_juliandate();
442             }
443            
444             sub _dotz{
445 1     1   2 my $self = shift;
446 1         13 my ($h,$m) = split(/:/,$self->{tz});
447 1 50       5 $m *= -1 if $h < 0; $h = $h + $m / 60.0;
  1         3  
448 1         3 $self->{tzone} = $h;
449             }
450            
451             sub _dolocn{
452 1     1   2 my $self = shift;
453 1         3 my ($lon,$lat) = split(/ /,$self->{locn});
454 1 50       4 my ($d,$m) = split(/:/,$lon); $m *= -1 if $d < 0; $lon = $d + $m / 60.0;
  1         5  
  1         2  
455 1 50       4 ($d,$m) = split(/:/,$lat); $m *= -1 if $d < 0; $lat = $d + $m / 60.0;
  1         4  
  1         3  
456 1         3 $self->{longitude} = $lon;
457 1         2 $self->{latitude} = $lat;
458             }
459            
460             sub _juliandate{
461 1     1   2 my $self = shift;
462 1         2 my $year = $self->{year};
463 1         2 my $month = $self->{month};
464 1         2 my $date = $self->{day};
465 1 50       4 if ( $month > 2 ) {
466 1         2 $month -= 3;
467             }else {
468 0         0 $month += 9; $year -= 1;
  0         0  
469             }
470 1         3 my $tod = $self->{time} / 24.0; #part of the curr. day.
471 1         3 my $c = int($year/100); $year %= 100;
  1         2  
472 1         8 return (int(146097*$c/4) +
473             int(1461*$year/4) +
474             int((153*$month +2)/5) +
475             $date) +
476             1721118.5+ $tod;
477             }
478            
479             sub _getdatetime{
480 0     0     my $self = shift;
481 0           my $dayno = $self->{jdate} +0.5 +$self->{tzone}/24.0;
482 0           my $i = int($dayno); my $f = $dayno-$i;
  0            
483 0           my $b = $i;
484 0 0         if ( $i > 2299160 ){
485 0           my $a = int(($i - 1867216.25)/36524.25);
486 0           $b = $i + 1 + $a - int($a/4);
487             }
488 0           my $c = $b + 1524;
489 0           my $d = int(($c-122.1)/365.25);
490 0           my $e = int(365.25*$d);
491 0           my $g = int(($c-$e)/30.6001);
492 0           my $day = $c -$e +$f -int(30.6001*$g);
493 0           my $mon = $g -1;
494 0 0         $mon -= 12 if $g > 13.5;
495 0           my $year = $d - 4715;
496 0 0         $year -= 1 if $mon > 2.5;
497 0           $self->{time} = $day - int($day);
498 0           $self->{day} = int($day);
499 0           $self->{month} = $mon;
500 0           $self->{year} = $year;
501             }
502            
503             sub ymd{
504 0     0 0   my $self = shift;
505 0 0         $self->_getdatetime unless $self->{year};
506 0           return ($self->{year}, $self->{month},
507             $self->{day}, $self->{time}*24.0);
508             }
509            
510             sub jdate{
511 0     0 0   my $self = shift;
512 0           return $self->{jdate};
513             }
514            
515             sub moon{
516 0     0 1   my $self = shift;
517 0   0       my $time = shift || 0.0;
518 0           return Moon->new(
519             jdate => $self->{jdate},
520             tzone => $self->{tzone},
521             latitude => $self->{latitude},
522             longitude => $self->{longitude},
523             );
524 0           return $self->{Moon};
525             };
526            
527             sub sun{
528 0     0 0   my $self = shift;
529 0   0       my $time = shift || 0.0;
530 0           return Sun->new(
531             jdate => $self->{jdate},
532             tzone => $self->{tzone},
533             latitude => $self->{latitude},
534             longitude => $self->{longitude},
535             );
536             };
537            
538             # =========================================================================================
539             # S e r v i c e : D a y o f t h e w e e k
540             # =========================================================================================
541             sub weekday{
542 0     0 0   my $self = shift;
543 0           return int($self->{jdate}+2) % 7;
544             }
545            
546             # =========================================================================================
547             # S e r v i c e : S u n r i s e / s e t
548             # =========================================================================================
549             sub sunriseset{
550 0     0 0   my $self = shift;
551 0           my $sun = $self->sun;
552 0   0       my $offset = shift || 0.0;
553 0           return $sun->riseset($offset);
554             }
555            
556             # =========================================================================================
557             # S e r v i c e : M o o n r i s e / s e t
558             # =========================================================================================
559             sub moonriseset{
560 0     0 0   my $self = shift;
561 0           my $moon = $self->moon;
562 0   0       my $offset = shift || 0.0;
563 0           return $moon->riseset($offset);
564             }
565            
566             # =========================================================================================
567             # T i t h i S e r v i c e
568             # =========================================================================================
569             sub tithi{
570 0     0 0   my $self = shift;
571 0           my $time = shift;
572 0           my $sun = $self->sun();
573 0           my $moon = $self->moon();
574 0           my $t;
575 0           $t = $moon->longitude($time) - $sun->longitude($time);
576 0 0         $t += 360 if $t < 0.0;
577 0           return $t / 12.0;
578             }
579            
580             # Compute tithi endings. At times there are two though most often just one.
581             # for example: Aug 6, 2003
582             sub tithi_endings{
583 0     0 0   my $self = shift;
584 0           my %th; # Hash of tithi endings at most 2 entries.
585 0 0         my ($t1, $tm1) = $self->_endtithi(-0.5); $th{$t1} = $tm1 if $tm1;
  0            
586 0 0         my ($t2, $tm2) = $self->_endtithi( 0.0); $th{$t2} = $tm2 if $tm2;
  0            
587 0 0         my ($t3, $tm3) = $self->_endtithi(+0.5); $th{$t3} = $tm3 if $tm3;
  0            
588 0           return %th;
589             }
590            
591             sub _endtithi{
592 0     0     my $self = shift;
593 0           my $st = shift;
594 0           my $t1 = $self -> tithi($st); # At the start of the cal. date.
595 0           my $tid = (int($t1))%30;
596 0           my $cnt = 0;
597 0           my $et = $st;
598 0           for (my $togo = 1.0; abs($togo) > 0.00001;){
599 0 0         if (int($t1) == $tid){
600 0           $togo = 1 - ($t1 - int($t1));
601             }else{
602 0           $togo = -($t1 - int($t1));
603             }
604 0           $et += $togo*27.5/24.0;
605 0           $t1 = $self->tithi($et);
606 0           $cnt ++;
607             }
608 0 0 0       return ($tid, $et*24.0) if $et >= 0.0 && $et < 1.0;
609 0           return (undef,undef);
610             }
611            
612             # =========================================================================================
613             # N a k s h y a t r a S e r v i c e
614             # =========================================================================================
615             sub nakshyatram{
616 0     0 0   my $self = shift;
617 0           my $time = shift;
618 0           my $moon = $self->moon();
619 0           my $t;
620 0           my $ay = $moon -> ayanamsa();
621 0           $t = $moon->longitude($time) + $ay;
622 0 0         $t += 360 if $t < 0.0;
623 0           return $t * 3.0 / 40.0 ;
624             }
625            
626             sub nakshyatra_endings{
627 0     0 0   my $self = shift;
628 0           my %th ; # Hash of nakshyatra endings at most 2 entries.
629 0 0         my ($t0, $tm0) = $self->_endnakshyatra(-1); $th{$t0} = $tm0 if $tm0;
  0            
630 0 0         my ($t1, $tm1) = $self->_endnakshyatra(-0.5); $th{$t1} = $tm1 if $tm1;
  0            
631 0 0         my ($t2, $tm2) = $self->_endnakshyatra( 0.0); $th{$t2} = $tm2 if $tm2;
  0            
632 0 0         my ($t3, $tm3) = $self->_endnakshyatra(+0.5); $th{$t3} = $tm3 if $tm3;
  0            
633 0 0         my ($t4, $tm4) = $self->_endnakshyatra(+1); $th{$t4} = $tm4 if $tm4;
  0            
634 0           return %th;
635             }
636            
637             sub _endnakshyatra{
638 0     0     my $self = shift;
639 0           my $st = shift;
640 0           my $t1 = $self -> nakshyatram($st); # At the start of the cal. date.
641 0           my $tid = (int($t1))%27;
642 0           my $cnt = 0;
643 0           my $et = $st;
644 0           for (my $togo = 1.0; abs($togo) > 0.00001;){
645 0 0         if (int($t1) == $tid){
646 0           $togo = 1 - ($t1 - int($t1));
647             }else{
648 0           $togo = -($t1 - int($t1));
649             }
650 0           $et += $togo*30/24.0;
651 0           $t1 = $self->nakshyatram($et);
652 0           $cnt ++;
653             }
654 0           return ($tid, $et*24.0);# if $et >= 0.0 && $et < 1.0;
655 0           return (undef,undef);
656             }
657            
658             # =========================================================================================
659             # S e r v i c e : k a r t e ( S u n c h a r a )
660             # =========================================================================================
661             # sunchara tracks the movement of the Sun on Zondiac of 27 starrs.
662             # For this we can assume uniform motion of the Sun, no problem.
663             sub sunchara{
664 0     0 0   my $self = shift;
665 0           my $n_sun = $self->sun->n_long() *108/360.0;
666 0           my $n_sun1 = $self->sun()->n_long(1.0) *108/360.0;
667 0 0         if (int($n_sun1) > int($n_sun)){
668 0           my $t = 24.0 * (int($n_sun1) - $n_sun)/($n_sun1 -$n_sun);
669 0           return ( int($n_sun1), $t );
670             }
671 0           return (undef, undef);
672             }
673            
674             # =========================================================================================
675             # S e r v i c e : L e n g t h o f d a y t i m e
676             # =========================================================================================
677             # How long we have the Sun on a given day?
678             sub daylength{
679 0     0 0   my $self = shift;
680 0           my $sun = $self->sun;
681 0           my ($rise, $set, $flag) = $sun->riseset();
682 0           return $set - $rise;
683             }
684            
685             # =========================================================================================
686             # S e r v i c e : N e w m o o n t i m i n g
687             # =========================================================================================
688             # Calculation of the moment of the nearest new moon in JD. (the error does not exceed 2 minutes). The result is Julian date/time in UT.
689             sub newmoon{
690 0     0 0   my $self = shift;
691 0           my $arg = shift; # 0 => past 1 => next.
692 0           my $knv = int((($self->{jdate} - 2415020.0) / 365.25) * 12.3685) + $arg ;
693 0           my $t = ($self->{jdate} - 2415020.0) / 36525.0;
694 0           my $t2 = $t*$t;
695 0           my $t3 = $t2*$t;
696 0           my $d2r = atan2(1.0,1.0) / 45.0;
697            
698 0           my $jdnv = 2415020.75933 + 29.53058868 * $knv + 0.0001178 * $t2 - 0.000000155 * $t3;
699 0           $jdnv += 0.00033 * sin((166.56 + 132.87 * $t - 0.009173 * $t2) * $d2r);
700 0           my $m = 359.2242 + 29.10535608 * $knv - 0.0000333 * $t2 - 0.00000347 * $t3;
701 0           my $ml = 306.0253 + 385.81691806 * $knv + 0.0107306 * $t2 + 0.00001236 * $t3;
702 0           my $f = 21.2964 + 390.67050646 * $knv - 0.0016528 * $t2 - 0.00000239 * $t3;
703 0           $m *= $d2r; $ml *= $d2r; $f *= $d2r;
  0            
  0            
704            
705 0           my $djd = (0.1734 - 0.000393 * $t) * sin($m) + 0.0021 * sin(2 * $m);
706 0           $djd = $djd - 0.4068 * sin($ml) + 0.0161 * sin(2 * $ml);
707 0           $djd = $djd - 0.0004 * sin(3 * $ml) + 0.0104 * sin(2 * $f) ;
708 0           $djd = $djd - 0.0051 * sin($m + $ml) - 0.0074 * sin($m - $ml);
709 0           $djd = $djd + 0.0004 * sin(2 * $f + $m) - 0.0004 * sin(2 * $f - $m);
710 0           $djd = $djd - 0.0006 * sin(2 * $f + $ml) + 0.001 * sin(2 * $f - $ml);
711 0           $djd = $djd + 0.0005 * sin($m + 2 * $ml);
712            
713 0           $jdnv += $djd;
714 0           return $jdnv;
715             }
716            
717             # =========================================================================================
718             # S e r v i c e : R a h u k a l a m
719             # =========================================================================================
720             sub rahu_kalam{
721 0     0 0   my $self = shift;
722 0           my $sun = $self->sun;
723 0           my ($rise, $set, $flag) = $sun->riseset();
724 0           my $d_len = $set - $rise;
725 0           my $weekday = $self->weekday();
726             # week day Sun Mon Tue Wed Thu Fri Sat
727 0           my $seg = [ 7, 1, 6, 4, 5, 3, 2 ];
728 0           my $t = $rise + $seg->[$weekday]*$d_len/8 ;
729 0           return ( $t, $t + $d_len/8 );
730             }
731             # =========================================================================================
732             # S e r v i c e : G u l i k a k a l a m
733             # =========================================================================================
734            
735             sub gulika_kalam{
736 0     0 0   my $self = shift;
737 0           my $sun = $self->sun;
738 0           my ($rise, $set, $flag) = $sun->riseset();
739 0           my $d_len = $set - $rise;
740 0           my $weekday = $self->weekday();
741             # week day Sun Mon Tue Wed Thu Fri Sat
742 0           my $seg = [ 6, 5, 4, 3, 2, 1, 0 ];
743 0           my $t = $rise + $seg->[$weekday]*$d_len/8 ;
744 0           return ( $t, $t + $d_len/8 );
745             }
746             # =========================================================================================
747             # S e r v i c e : Y a m a g a n d a K a l a m
748             # =========================================================================================
749            
750             sub yamaganda_kalam{
751 0     0 0   my $self = shift;
752 0           my $sun = $self->sun;
753 0           my ($rise, $set, $flag) = $sun->riseset();
754 0           my $d_len = $set - $rise;
755 0           my $weekday = $self->weekday();
756             # week day Sun Mon Tue Wed Thu Fri Sat
757 0           my $seg = [ 4, 3, 2, 1, 0, 6, 5 ];
758 0           my $t = $rise + $seg->[$weekday]*$d_len/8 ;
759 0           return ( $t, $t + $d_len/8 );
760             }
761            
762             # =========================================================================================
763             # S e r v i c e : D u r m u h u r t a m
764             # =========================================================================================
765             sub durmuhurtam{
766 0     0 0   my $self = shift;
767 0           my $sun = $self->sun;
768 0           my ($rise, $set, $flag) = $sun->riseset();
769 0           my $d_len = $set - $rise;
770 0           my $weekday = $self->weekday();
771 0           my $d1 = [ 13, 7, 3, 7, 11, 3, 0 ];
772 0           my $d2 = [ undef, 11, 10, undef, 12, 8, 1];
773             return (
774 0 0         $rise + $d1->[$weekday]*$d_len/15.0 ,
    0          
775             $rise + (1.0 + $d1->[$weekday])*$d_len/15.0 ,
776             $d2->[$weekday]? $rise + $d2->[$weekday]*$d_len/15.0 : undef ,
777             $d2->[$weekday]? $rise + (1.0 + $d2->[$weekday])*$d_len/15.0 : undef
778             );
779             }
780            
781             # =========================================================================================
782             # S e r v i c e : K a r a n a
783             # =========================================================================================
784             # Karana calculation.
785             sub karana{
786             # Karana is displacement of moon from sun in 6 deg segments.
787             # Tithi is displacement of moon from sun in 12 deg segments.
788 0     0 0   my $self = shift;
789 0           my $time = shift;
790 0           return 2 * $self->tithi($time) ;
791             }
792             sub karana_endings{
793 0     0 0   my $self = shift;
794 0           my %th ;
795 0 0         my ($t1, $tm1) = $self->_endkarana(-0.5); $th{$t1} = $tm1 if $tm1;
  0            
796 0 0         my ($t2, $tm2) = $self->_endkarana( 0.0); $th{$t2} = $tm2 if $tm2;
  0            
797 0 0         my ($t3, $tm3) = $self->_endkarana(+0.5); $th{$t3} = $tm3 if $tm3;
  0            
798 0           return %th;
799             }
800             sub _endkarana{
801 0     0     my $self = shift;
802 0           my $st = shift;
803 0           my $t1 = $self -> karana($st); # At the start of the cal. date.
804 0           my $tid = (int($t1))%60;
805 0           my $cnt = 0;
806 0           my $et = $st;
807 0           for (my $togo = 1.0; abs($togo) > 0.00001;){
808 0 0         if (int($t1) == $tid){
809 0           $togo = 1 - ($t1 - int($t1));
810             }else{
811 0           $togo = -($t1 - int($t1));
812             }
813 0           $et += $togo*27.5/48.0;
814 0           $t1 = $self->karana($et);
815 0           $cnt ++;
816             }
817 0 0 0       return ($tid, $et*24.0) if $et >= 0.0 && $et < 1.0;
818 0           return (undef,undef);
819             }
820             # =========================================================================================
821             # S e r v i c e : Y o g a
822             # =========================================================================================
823             # Yoga calculation.
824             sub yoga{
825             # yoga is the sum of longitudes of the lights, the Sun and Moon in segments of 12 degrees.
826 0     0 0   my $self = shift;
827 0           my $time = shift;
828 0           my $sun = $self->sun();
829 0           my $moon = $self->moon();
830 0           my $t;
831 0           $t = $moon->n_long($time) + $sun->n_long($time);
832 0 0         $t -= 360 if $t > 360.0;
833 0           return $t * 3.0 / 40.0;
834             }
835             sub yoga_endings{
836 0     0 0   my $self = shift;
837 0           my %th ; # Hash of tithi endings at most 2 entries.
838 0 0         my ($t1, $tm1) = $self->_endyoga(-0.5); $th{$t1} = $tm1 if $tm1;
  0            
839 0 0         my ($t2, $tm2) = $self->_endyoga( 0.0); $th{$t2} = $tm2 if $tm2;
  0            
840 0 0         my ($t3, $tm3) = $self->_endyoga(+0.5); $th{$t3} = $tm3 if $tm3;
  0            
841 0           return %th;
842             }
843             sub _endyoga{
844 0     0     my $self = shift;
845 0           my $st = shift;
846 0           my $t1 = $self -> yoga($st); # At the start of the cal. date.
847 0           my $tid = (int($t1))%27;
848 0           my $cnt = 0;
849 0           my $et = $st;
850 0           for (my $togo = 1.0; abs($togo) > 0.00001;){
851 0 0         if (int($t1) == $tid){
852 0           $togo = 1 - ($t1 - int($t1));
853             }else{
854 0           $togo = -($t1 - int($t1));
855             }
856 0           $et += $togo*27.5/24.0;
857 0           $t1 = $self->yoga($et);
858 0           $cnt ++;
859             }
860 0 0 0       return ($tid, $et*24.0) if $et >= 0.0 && $et < 1.0;
861 0           return (undef,undef);
862             }
863             # =========================================================================================
864             # S e r v i c e : V a r j y a m
865             # =========================================================================================
866             # This service returns any varjyas for this day in an array.
867             # The times given are starting times. Each varjya ends in 1:30 hrs
868             # from the its starting time.
869             #
870             # Aswini 50; Bharani 4; Krittika 30; Rohini 40; Mrigasira 14; Aridra 21;
871             # Punarvasu 30; Pushya 20; Aslesha 32; Makha 30; Pubba 20; Uttara 1;
872             # Hasta 21; Chitta 20; Swati 14; Visakha 14; Anuradha 10; Jyeshta 14;
873             # Moola 20; Poorvashadha 20; Uttarashadha 20; Sravana 10; Dhanishta 10;
874             # Satabhisha 18; Poorvabhadra 16; Uttarabhadra and Revati 30
875            
876             my $tyajyam = [
877             50, 4, 30, 40, 14, 21, 30, 20, 32,
878             30, 20, 1, 21, 20, 14, 14, 10, 14,
879             20, 20, 20, 10, 10, 18, 16, 30, 30,
880             ];
881            
882             sub varjyam{
883 0     0 0   my $self = shift;
884 0           my @out;
885 0           my %nk = $self->nakshyatra_endings();
886 0           for my $t (sort keys %nk){
887 0           my $prev = $t -1;
888 0 0         next unless $nk{$prev};
889 0           my $cur_nk = $t;
890 0           my $dur_nk = $nk{$t} - $nk{$prev};
891 0           my $v = ($tyajyam -> [$t] / 60.0) * $dur_nk;
892 0           $v += $nk{$prev};
893 0 0 0       push(@out,$v) if $v > 0 && $v <= 24.00;
894             }
895 0           return @out;
896             }
897            
898             1;
899             # ======================================================================
900            
901             # ======================================================================
902             __END__