Guest User

sunrise.pl

a guest
Dec 16th, 2010
1,218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 4.08 KB | None | 0 0
  1. #!/usr/bin/env perl
  2. $^W = 1;
  3. use strict;
  4. use Getopt::Long;
  5. use DateTime;
  6. use DateTime::Astro::Sunrise;
  7.  
  8. my $cvsid = '$Id: sunrise,v 1.2 2010-12-16 21:06:56 gilles Exp $';
  9.  
  10. my %altitudes =
  11.   (
  12.    center => 0, # center of sun's disk touches a mathematical horizon
  13.    limb => -0.25, # sun's upper limb touches a mathematical horizon
  14.    rcenter => -0.583, # center of sun's disk looks like it touches the horizon
  15.    rlimb => -0.833, # sun's upper limb looks like it touches the horizon
  16.    civil => -6, # reading outside requires artificial illumination
  17.    nautical => -12, # navigation using a sea horizon no longer possible
  18.    amateur => -15, # the sky is dark enough for most astronomical observations
  19.    astronomical => -18, # the sky is completely dark
  20.   );
  21.  
  22. sub help_and_exit {
  23.     print "Usage: $0 [OPTION]...", <<'EOF';
  24. Show the time of sunrise and sunset at the given location.
  25.  
  26.   -x, --longitude=NUM   longitude (degrees, >0 for east or xxxE or xxxW)
  27.   -y, --latitude=NUM    latitude (degrees, >0 for north or xxxN or xxxS)
  28.   -a, --altitude=NUM    sun altitude (pass 'help' to list symbolic names)
  29.   -i, --iter=N          number of iterations (rarely needed)
  30.   -f, --format=FORMAT   time display format
  31.   -d, --date=DATE       day to consider (default: today)
  32.       --help            display this help and exit
  33.       --version         output version information and exit
  34. EOF
  35.     exit;
  36. }
  37.  
  38. sub version_and_exit {
  39.     print "sunrise $cvsid\n";
  40.     exit;
  41. }
  42.  
  43. sub validate_xy {
  44.     my ($s, $name, $neg, $pos) = @_;
  45.     die "No $name specified!" unless defined $s;
  46.     $s =~ tr/\t //;
  47.     my $negative = ($s =~ s/^([-+])// && $1 eq '-');
  48.     my $opposite = ($s =~ s/(\Q$pos\E|\Q$neg\E)$//i && lc($1) eq lc($neg));
  49.     my $sign = ($negative ^ $opposite ? '-' : '+');
  50.     die "Badly formed number in $name!\n"
  51.       unless $s =~ /^(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)$/;
  52.     $s .= ".0" unless $s =~ /\./;
  53.     return "$sign$s";
  54. }
  55.  
  56. sub sun_rise_set {
  57.     my ($long, $lat, $alt, $iter, $dt) = @_;
  58.     my $sr = DateTime::Astro::Sunrise->new($long, $lat, $alt, $iter);
  59.     my ($rise, $set) = $sr->sunrise($dt);
  60.     my $tz = $dt->time_zone;
  61.     $rise->set_time_zone($tz);
  62.     $set->set_time_zone($tz);
  63.     return $rise, $set;
  64. }
  65.  
  66. sub main {
  67.     ## Default values
  68.     my ($long, $lat) = (undef, undef);
  69.     my $alt = $altitudes{rlimb};
  70.     my $iter = 3;
  71.     my $locale = "en_IE";
  72.     my $time_format = "%c %Z";
  73.     my $dt = undef;
  74.  
  75.     ## Command line parsing
  76.     GetOptions(
  77.                "x|longitude=s" => \$long,
  78.                "y|latitude=s" => \$lat,
  79.                "a|altitude=s" => \$alt,
  80.                "i|iter=i" => \$iter,
  81.                "f|format=s" => \$time_format,
  82.                "d|date=s" => \$dt,
  83.                "help" => \&help_and_exit,
  84.                "version" => \&version_and_exit,
  85.                ) or die "$0: invalid command line (try --help)\n";
  86.     # TODO: options for locale?, timezone
  87.     if ($alt eq 'help') {
  88.         foreach my $z (sort {$a->[1] <=> $b->[1]}
  89.                        map {[$_,$altitudes{$_}]} keys %altitudes) {
  90.             printf "%-19s %g\n", @$z;
  91.         }
  92.         exit;
  93.     }
  94.     $long = validate_xy($long, "longitude", "w", "e");
  95.     $lat = validate_xy($lat, "latitude", "s", "n");
  96.     $alt = $altitudes{lc($alt)} if exists $altitudes{lc($alt)};
  97.     die "Badly formed altitude (try --altitude=help)!"
  98.       unless $alt =~ /^[-+]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)$/;
  99.     if (defined $dt) {
  100.         require Date::Manip;
  101.         $dt = DateTime->new(
  102.                 Date::Manip::UnixDate(
  103.                   Date::Manip::ParseDateString($dt),
  104.                   qw[year %Y month %m day %d],
  105.                   qw[hour %H minute %M second %S],
  106.                   qw[time_zone %z]));
  107.     } else {
  108.         $dt = DateTime->now;
  109.         $dt->set_time_zone("local");
  110.     }
  111.     ## Compute and display
  112.     my ($rise, $set) = sun_rise_set($long, $lat, $alt, $iter, $dt);
  113.     $rise->set_locale($locale);
  114.     $set->set_locale($locale);
  115.     print $rise->strftime($time_format), "\n";
  116.     print $set->strftime($time_format), "\n";
  117. }
  118.  
  119. main(@ARGV);
Advertisement
Add Comment
Please, Sign In to add comment