1#!/usr/local/bin/perl
2
3# Display Sun and Moon rise and set for a pre-programmed position. The
4# -help option gets you help.
5
6use 5.006002;
7
8use strict;
9use warnings;
10
11use Astro::Coord::ECI;
12use Astro::Coord::ECI::Sun;
13use Astro::Coord::ECI::Moon;
14use Astro::Coord::ECI::Utils qw{deg2rad};
15use Getopt::Long 2.33;
16use Pod::Usage;
17use POSIX qw{strftime};
18use Time::Local;
19
20our $VERSION = '0.122';
21
22Getopt::Long::Configure( 'pass_through' );	# Numbers may be negative.
23
24my %opt = (
25    format => '%d-%b-%Y %H:%M:%S',
26);
27
28GetOptions( \%opt,
29    qw{ date=s format=s moon! sun! tomorrow! },
30    help => sub { pod2usage( { -verbose => 2 } ) },
31) or pod2usage( { -verbose => 0 } );
32
33my @args = @ARGV;
34@args
35    or not defined $ENV{ALMANAC_POSITION}
36    or @args = split '\s+', $ENV{ALMANAC_POSITION};
37@args
38    or @args = ( 38.898748, -77.037684, 16.68 );
39
40$opt{sun}
41    or $opt{moon}
42    or $opt{sun} = $opt{moon} = 1;
43
44#	Stash position where it's convenient.
45
46my ( $lat, $lon, $hgt ) = @args;
47
48#	Start time is the previous midnight. Unless -tomorrow is
49#	set, in which case it's the next midnight.
50
51my $start;
52if ( defined $opt{date} ) {
53    require Date::Manip;
54    $start = Date::Manip::UnixDate( $opt{date}, '%s' )
55	or die "Invalid date $opt{date}\n";
56} else {
57    $start = timelocal (0, 0, 0, (localtime)[3 .. 5]);
58    $start += 86400 if $opt{tomorrow};
59}
60
61#	The end time is the start time + 1 day.
62
63my $end = $start + 86400;
64
65#	Create an object representing our location. Remember that
66#	angles are in radians, and distance in kilometers.
67
68my $loc = Astro::Coord::ECI->geodetic(
69    deg2rad( $lat ), deg2rad( $lon ), $hgt/1000 );
70
71#	Generate the almanac data for the Sun and Moon if each is
72#	desired. We instantiate the luminary, call almanac() on it, and
73#	then throw it away.
74
75my @almanac;
76foreach my $luminary ( qw{ sun moon } ) {
77    $opt{$luminary}
78	or next;
79    my $class = 'Astro::Coord::ECI::' . ucfirst $luminary;
80    push @almanac, $class->new( station => $loc )->almanac(
81	$start, $end );
82}
83
84#	Display the time and the text description of the events, in
85#	order of increasing time.
86
87foreach (sort {$a->[0] <=> $b->[0]} @almanac) {
88    print strftime ($opt{format}, localtime $_->[0]), '  ',
89	ucfirst ($_->[3]), "\n";
90}
91
92__END__
93
94=head1 TITLE
95
96almanac - Generate almanac data for a given location
97
98=head1 SYNOPSIS
99
100 almanac       # The White House by default
101 almanac 52.07 4.29 4   # The Hague
102 almanac -help
103 almanac -version
104
105=head1 OPTIONS
106
107=head2 -date=date_string
108
109This option specifies the date as a string that can be parsed by
110L<Date::Manip|Date::Manip>. If L<Date::Manip|Date::Manip> can not be
111loaded an error occurs. If this option is specified, C<-tomorrow> is
112ignored.
113
114=head2 -format=strftime_format
115
116This option specifies the C<strftime> format used to display dates and
117times. The default is C<'%d-%b-%Y %H:%M:%S'>.
118
119=head2 -help
120
121This option displays the documentation for this script. The script then
122exits.
123
124=head2 -moon
125
126Display data for the Moon. Defaults to C<-nomoon> if C<-sun> is
127asserted.
128
129=head2 -sun
130
131Display data for the Sun. Defaults to C<-nosun> if C<-moon> is asserted.
132
133=head2 -tomorrow
134
135Display data for tomorrow, rather than today.
136
137=head2 -version
138
139This option displays the version of this script. The script then exits.
140
141=head1 DETAILS
142
143This Perl script displays today's almanac for the position given on the
144command line, in latitude north of the Equator, longitude east of the
145prime meridian, and meters above sea level. If no position is given on
146the command line, the contents of environment variable
147C<ALMANAC_POSITION> are broken on spaces and used as the posiiton. If
148this environment variable is not found, the position of the White House
149in Washington DC USA is used.
150
151By default, data for both the Sun and Moon are displayed. If you
152explicitly assert either C<-sun> or C<-moon>, only the selected luminary
153will be displayed.
154
155You can look a day ahead by specifying C<-tomorrow>.
156
157The format of the time output can be specified using the C<-format>
158option.
159
160=head1 AUTHOR
161
162Thomas R. Wyant, III F<wyant at cpan dot org>
163
164=head1 COPYRIGHT AND LICENSE
165
166Copyright (C) 2012-2021 by Thomas R. Wyant, III
167
168This program is free software; you can redistribute it and/or modify it
169under the same terms as Perl 5.10.0. For more details, see the full text
170of the licenses in the directory LICENSES.
171
172This program is distributed in the hope that it will be useful, but
173without any warranty; without even the implied warranty of
174merchantability or fitness for a particular purpose.
175
176=cut
177
178# ex: set textwidth=72 :
179