31

Is there a simple open-source, command-line program that can show the sunrise and sunset times at a given date and location, and perhaps moon and planet data as well?

Browsing the Debian package database and Google searches, I can't find anything relevant. This surprises me — considering the number of people who are both astronomy geeks and unix geeks, I'd have expected a de-facto-standard sunrise(1) (or perhaps sunrise(6)).

I am not interested in more complex programs that incidentally perform the calculations, such as sky maps (celestia, kstars, starplot, stellarium), earth maps (sunclock, xplanet), calendars/agendas (emacs, remind), clocks (glunarclock, wmsun), tide almanachs (xtide). There is perhaps aa (astronomical-almanac), but I don't see a simple way of asking it what time the sun will rise on this date at these longitude and latitude.

What did I miss?

9 Answers 9

18

Did you try sunwait?

Sunwait is a small C program for calculating sunrise and sunset, as well as civil, nautical, and astronomical twilights. [..]

The project is available on GitHub and can be cloned as follows:

$ git clone https://github.com/risacher/sunwait Cloning into 'sunwait'... remote: Enumerating objects: 107, done. remote: Counting objects: 100% (62/62), done. remote: Compressing objects: 100% (26/26), done. remote: Total 107 (delta 45), reused 37 (delta 36), pack-reused 45 Receiving objects: 100% (107/107), 121.93 KiB | 2.65 MiB/s, done. Resolving deltas: 100% (55/55), done. $ cd sunwait/ 

After fixing issues with parentheses, the program can be built

$ make gcc -c -Wall sunwait.cpp -o sunwait.o gcc -c -Wall sunriset.cpp -o sunriset.o sunriset.cpp: In function ‘void sun_RA_dec(double, double*, double*, double*)’: sunriset.cpp:151:18: warning: variable ‘zs’ set but not used [-Wunused-but-set-variable] 151 | double xs, ys, zs; | ^~ gcc -c -Wall print.cpp -o print.o gcc sunwait.o sunriset.o print.o -o sunwait -lm -lstdc++ 
$ ./sunwait help Calculate sunrise and sunset times for the current or targetted day. The times can be adjusted either for twilight or fixed durations. The program can either: wait for sunrise or sunset (function: wait), or return the time (GMT or local) the event occurs (function: list), or report the day length and twilight timings (function: report), or simply report if it is DAY or NIGHT (function: poll). You should specify the latitude and longitude of your target location. Usage: sunwait [major options] [minor options] [twilight type] [rise|set] [offset] [latitude] [longitude] Major options, either: poll Returns immediately indicating DAY or NIGHT. See 'program exit codes'. Default. wait Sleep until specified event occurs. Else exit immediate. list [X] Report twilight times for next 'X' days (inclusive). Default: 1. report Generate a report about the days sunrise and sunset timings. Minor options, any of: [no]debug Print extra info and returns in one minute. Default: nodebug. [no]version Print the version number. Default: noversion. [no]help Print this help. Default: nohelp. [no]gmt Print times in GMT or local-time. Default: nogmt. Twilight types, either: daylight Top of sun just below the horizon. Default. civil Civil Twilight. -6 degrees below horizon. nautical Nautical twilight. -12 degrees below horizon. astronomical Astronomical twilight. -18 degrees below horizon. angle [X.XX] User-specified twilight-angle (degrees). Default: 0. Sunrise/sunset. Only useful with major-options: 'wait' and 'list'. Any of: (default: both) rise Wait for the sun to rise past specified twilight & offset. set Wait for the sun to set past specified twilight & offset. Offset: offset [MM|HH:MM] Time interval (+ve towards noon) to adjust twilight calculation. Target date. Only useful with major-options: 'report' or 'list'. Default: today d [DD] Set the target Day-of-Month to calculate for. 1 to 31. m [MM] Set the target Month to calculate for. 1 to 12. y [YYYY] Set the target Year to calculate for. 2000 to 2099. latitude/longitude coordinates: floating-point degrees, with [NESW] appended. Default: Bingham, England. Exit (return) codes: 0 OK: exit from 'wait' or 'list' only. 1 Error. 2 Exit from 'poll': it is DAY or twilight. 3 Exit from 'poll': it is NIGHT (after twilight). Example 1: sunwait wait rise offset -1:15:10 51.477932N 0.000000E Wait until 1 hour 15 minutes 10 secs before the sun rises in Greenwich, London. Example 2: sunwait list 7 civil 55.752163N 37.617524E List civil sunrise and sunset times for today and next 6 days. Moscow. Example 3: sunwait poll exit angle 10 54.897786N -1.517536E Indicate by program exit-code if is Day or Night using a custom twilight angle of 10 degrees above horizon. Washington, UK. Example 4: sunwait list 7 gmt sunrise angle 3 List next 7 days sunrise times, custom +3 degree twilight angle, default location. Uses GMT; as any change in daylight saving over the specified period is not considered. Note that program uses C library functions to determine time and localtime. Error for timings are estimated at: +/- 4 minutes. 

To install it globally, type:

$ sudo install -vpm 755 sunwait /usr/local/bin/ 'sunwait' -> '/usr/local/bin/sunwait' 
1
  • The syntax for specifying a particular date is a bit unusual and not that obvious in the docs: sunwait list d 05 m 08 y 24 51.48162049691373N 0.000E Commented Aug 5, 2024 at 13:12
11

For lazy bones as I am there is a very simple program called hdate, available in many distributions (apt-get install hdate on Debian/Ubuntu/…):

hdate -s -l N50 -L E14 -z2 

Output:

Wednesday, 26 June 2019, 23 Sivan 5779 sunrise: 04:55 sunset: 21:17 

Options:

  • -s sunset sunrise
  • -l, -L: Altitude and Latitude of Prague (50°05′N 14°25′E)
  • -z zone: SELC=+2

תודה רבה יהודים חכמים. :-)

0
11

I ended up using Perl's DateTime::Event::Sunrise (formerly DateTime::Astro::Sunrise), because it tends to be easier for me to deploy a module from CPAN than to compile C programs.

Sample usage:

use DateTime; use DateTime::Event::Sunrise; $latitude = "+48.857"; $longitude = "+2.351"; $sr = DateTime::Astro::Sunrise->new($longitude, $latitude, 0, 3); $date = DateTime->now; $date->set_time_zone("local"); ($rise, $set) = $sr->sunrise($date); $rise->set_time_zone("local"); $set->set_time_zone("local"); print $rise, " to ", $set, "\n"; 

My complete sunrise script:

#!/usr/bin/env perl $^W = 1; use strict; use Getopt::Long; use DateTime; use DateTime::Event::Sunrise; my $cvsid = '$Id$'; my %altitudes = ( center => 0, # center of sun's disk touches a mathematical horizon limb => -0.25, # sun's upper limb touches a mathematical horizon rcenter => -0.583, # center of sun's disk looks like it touches the horizon rlimb => -0.833, # sun's upper limb looks like it touches the horizon civil => -6, # reading outside requires artificial illumination nautical => -12, # navigation using a sea horizon no longer possible amateur => -15, # the sky is dark enough for most astronomical observations astronomical => -18, # the sky is completely dark ); sub help_and_exit { print "Usage: $0 [OPTION]...", <<'EOF'; Show the time of sunrise and sunset at the given location. -x, --longitude=NUM longitude (degrees, >0 for east or xxxE or xxxW) -y, --latitude=NUM latitude (degrees, >0 for north or xxxN or xxxS) -a, --altitude=NUM sun altitude (pass 'help' to list symbolic names) -i, --iter=N number of iterations (rarely needed) -f, --format=FORMAT time display format -d, --date=DATE day to consider (default: today) --help display this help and exit --version output version information and exit EOF exit; } sub version_and_exit { print "sunrise $cvsid\n"; exit; } sub validate_xy { my ($s, $name, $neg, $pos) = @_; die "No $name specified!" unless defined $s; $s =~ tr/\t //; my $negative = ($s =~ s/^([-+])// && $1 eq '-'); my $opposite = ($s =~ s/(\Q$pos\E|\Q$neg\E)$//i && lc($1) eq lc($neg)); my $sign = ($negative ^ $opposite ? '-' : '+'); die "Badly formed number in $name!\n" unless $s =~ /^(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)$/; $s .= ".0" unless $s =~ /\./; return "$sign$s"; } sub sun_rise_set { my ($long, $lat, $alt, $iter, $dt) = @_; my $sr = DateTime::Event::Sunrise->new($long, $lat, $alt, $iter); my ($rise, $set) = $sr->sunrise($dt); my $tz = $dt->time_zone; $rise->set_time_zone($tz); $set->set_time_zone($tz); return $rise, $set; } sub main { ## Default values my ($long, $lat) = (undef, undef); my $alt = $altitudes{rlimb}; my $iter = 3; my $locale = "en_IE"; my $time_format = "%c %Z"; my $dt = undef; ## Command line parsing GetOptions( "x|longitude=s" => \$long, "y|latitude=s" => \$lat, "a|altitude=s" => \$alt, "i|iter=i" => \$iter, "f|format=s" => \$time_format, "d|date=s" => \$dt, "help" => \&help_and_exit, "version" => \&version_and_exit, ) or die "$0: invalid command line (try --help)\n"; # TODO: options for locale?, timezone if ($alt eq 'help') { foreach my $z (sort {$a->[1] <=> $b->[1]} map {[$_,$altitudes{$_}]} keys %altitudes) { printf "%-19s %g\n", @$z; } exit; } $long = validate_xy($long, "longitude", "w", "e"); $lat = validate_xy($lat, "latitude", "s", "n"); $alt = $altitudes{lc($alt)} if exists $altitudes{lc($alt)}; die "Badly formed altitude (try --altitude=help)!" unless $alt =~ /^[-+]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)$/; if (defined $dt) { require Date::Manip; $dt = DateTime->new( Date::Manip::UnixDate( Date::Manip::ParseDateString($dt), qw[year %Y month %m day %d], qw[hour %H minute %M second %S], qw[time_zone %z])); } else { $dt = DateTime->now; $dt->set_time_zone("local"); } ## Compute and display my ($rise, $set) = sun_rise_set($long, $lat, $alt, $iter, $dt); $rise->set_locale($locale); $set->set_locale($locale); print $rise->strftime($time_format), "\n"; print $set->strftime($time_format), "\n"; } main(@ARGV); 
0
5

For Python there's the astral module. It's not command line, but implementing a command line program using it should be trivial (like your Perl example). Documentation and examples are at http://astral.readthedocs.io/en/latest/index.html.

3

Check out this Linux Home Automation Linux Home Automation site and search the page for "sunrise". There are some command line programs there from c. 1985 that are pretty minimalist. I have the source code for a number of related programs from that era, but I can't find them on the web.

Update: I just found the source for a few others, including sdate, on this Event Logger page. Search the page for "rise_set".

Update 2017-12-23: The Linux Home Automation project has moved, but it looks like the command-line programs for sunrise, sunset, etc., are still available here and here. I crossed out the link to the original page but kept it for reference and added a link to the new page.

0
2

This https://github.com/Aygath/zon program prints what you want, for sun rise/set/azimuth-altitude.

In the "releases" of my github you will find a .deb installation file for amd64 Debian and Ubuntu. It will build on ARM (raspberry pi) as well.

Moon data is in my plans, but not implemented yet.

It is suitable for your personal scheduling needs. It is targeted at scheduling with "systemd-run --calendar" or "at" command.

2

FYI on macOS (at least 14.6.1):

% /usr/libexec/corebrightnessdiag sunschedule Night Shift Sunset/Sunrise { isDaylight = 0; nextSunrise = "2024-09-12 20:04:10 +0000"; nextSunset = "2024-09-13 07:43:33 +0000"; previousSunrise = "2024-09-10 20:07:00 +0000"; previousSunset = "2024-09-11 07:42:07 +0000"; sunrise = "2024-09-11 20:05:35 +0000"; sunset = "2024-09-12 07:42:50 +0000"; } 
1

If you already have Dianne Skoll's remind installed―and you should, if you want an excellent command-line reminders program―it will do this. Create a "reminders" file, e.g., sun.rem, containing these two lines:

BANNER % REM Sunrise: [sunrise()] Sunset: [sunset()] 

and run it thus:

remind sun.rem

It also offers dates around moon phases. I haven't figured out the fine points of those yet.


Another possibility, suggested by Ms. Skoll in the mailing list:

# File day-or-night.rem BANNER % IF now() < sunrise() || now() > sunset() MSG night% ELSE MSG day% ENDIF 

I switched to that because it saves me a call to awk.


Here's a shell script that supports custom dates and locations.

#!/bin/sh set -eu date= # today longitude=2.352 latitude=48.857 # Paris NAME='Sunrise/sunset' FUNCTION1='sunrise' FUNCTION2='sunset' usage () { cat <<EOF Usage: $0 [-d DATE] Show the sunrise and sunset times. This program requires remind (https://dianne.skoll.ca/projects/remind/). -a ALT Sun altitude (ALT=(civil|nautical|sun)) -d DATE Date (default: today). -x NUM longitude (degrees, >0 for east or xxxE or xxxW) -y NUM latitude (degrees, >0 for north or xxxN or xxxS) EOF } while getopts a:d:x:y: OPTLET; do case $OPTLET in a) case $OPTARG in # Sloppy validation to keep things simple [Aa]*) NAME='Astronomical' FUNCTION1='adawn' FUNCTION2='adusk';; [Cc]*) NAME='Civil' FUNCTION1='dawn' FUNCTION2='dusk';; [Nn]*) NAME='Nautical' FUNCTION1='ndawn' FUNCTION2='ndusk';; [Ss]*) NAME='Sunrise/sunset' FUNCTION1='sunrise' FUNCTION2='sunset';; *) echo 1>&2 "Invalid altitude specification: $OPTARG"; exit 120;; esac;; d) date="'$(date -d "$OPTARG" +%Y-%m-%d)'";; x) case $OPTARG in *[Ee]) longitude=${OPTARG%?};; -*[Ww]) longitude=${OPTARG%?}; longitude=${longitude#-};; *[Ww]) longitude=-${OPTARG%?};; *) longitude=$OPTARG;; esac;; y) case $OPTARG in *[Nn]) latitude=${OPTARG%?};; -*[Ss]) latitude=${OPTARG%?}; latitude=${latitude#-};; *[Ss]) latitude=-${OPTARG%?};; *) latitude=$OPTARG;; esac;; ?) usage >&2; exit 120;; esac done remind - <<EOF BANNER % SET \$Longitude "$longitude" SET \$Latitude "$latitude" REM MSG $date $NAME: [$FUNCTION1($date)] [$FUNCTION2($date)]% EOF 
1
  • @Gilles 'SO- stop being evil' You really should put the script you wrote in its own answer rather than letting me get credit for it. Commented Feb 22, 2024 at 23:23
0

Btw, in Plan 9 from outer sp... er, Bell Labs, it's astro.

enter image description here

1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.