How to compute rise/set times and altitude above horizon

By Paul Schlyter, Stockholm, Sweden
email: or WWW:

Break out of a frame

How to compute planetary positions
Tutorial with numerical test cases

1. Computing the Sun's altitude above the horizon

First we compute the Sun's RA and Decl for this moment, as outlined
earlier. Now we need to know our Local Sidereal Time. We start by computing the sidereal time at Greenwich at 00:00 Universal Time, let's call this quantity GMST0:

    GMST0 = L + 180
L is the Sun's mean longitude, which we compute as:
    L = M + w
Note that we express GMST in degrees here to simplify the computations. 360 degrees of course corresponds to 24 hours, i.e. each hour corresponds to 15 degrees.

Now we can compute our Local Sidereal Time (LST):

    LST = GMST0 + UT*15.0 + long
UT is the Universal Time, expressed in hours+decimals, the remaining quantities are expressed in degrees. To convert UT to degrees we must multiply it by 15 above. long is our local longitude in degrees, where east longitude counts as positive, and west longitude as negative. (this is according to the geographic standard, and the recent astronomical standard; if you prefer to use the older astronomical standard where west longitude counts as positive, then you must change the '+' in front of 'long' to a '-' above).

Next let's compute the Sun's Local Hour Angle (LHA), i.e. the angle the Earth has turned since the Sun last was in the south:

    LHA = LST - RA
A negative hour angle means the Sun hasn't been in the south yet, this day. The angle -10 degrees is of course the same as 350 degrees, i.e. adding or subtracting even multiples of 360 degrees does not change the angle.

We also need to know our latitude (lat), where north latitude counts as poisitive and south latitude as negative. Now we can compute the Sun's altitude above the horizon:

    sin(h) = sin(lat) * sin(Decl) + cos(lat) * cos(Decl) * cos(LHA)
We compute sin(h), and then take the arcsine of this to get h, the Sun's altitude above the horizon.

2. Computing the Sun's rise/set times.

This is really the inverse of the previous problem, where we computed the Sun's altitude at a specific moment. Now we want to know at which moment the Sun reaches a specific altitude.

First we must decide which altitude we're interested in:

h = 0 degrees: Center of Sun's disk touches a mathematical horizon
h = -0.25 degrees: Sun's upper limb touches a mathematical horizon
h = -0.583 degrees: Center of Sun's disk touches the horizon; atmospheric refraction accounted for
h = -0.833 degrees: Sun's upper limb touches the horizon; atmospheric refraction accounted for
h = -6 degrees: Civil twilight (one can no longer read outside without artificial illumination)
h = -12 degrees: Nautical twilight (navigation using a sea horizon no longer possible)
h = -15 degrees: Amateur astronomical twilight (the sky is dark enough for most astronomical observations)
h = -18 degrees: Astronomical twilight (the sky is completely dark)

As you can see, there are several altitides to choose among. In most countries an altitude of -0.833 degrees is used to compute sunrise/set times (Sun's upper limb touches the horizon; atmospheric refraction accounted for). One exception is the Swedish national alamancs, which use -0.583 degrees (Center of Sun's disk touches the horizon; atmospheric refraction accounted for) - however my own Swedish almanac
Stjärnhimlen ("The Starry Sky") uses the international convention of -0.833 degrees.

When we've decided on some value for the altitude above the horizon, we start by computing the Sun's RA at noon local time. When the Local Sidereal Time equals the Sun's RA, then the Sun is in the south:

    LST  =  RA
which yields:

    GMST0 + UT*15.0 + long  = RA
Since we know GMST, long, and RA, it's now a simple matter to compute UT (GMST0 should also be computed at noon local time):

    UT_Sun_in_south = ( RA - GMST0 - long ) / 15.0
Now we're going to compute the Sun's Local Hour Angle (LHA) at rise/set (or at twilight, if we've decided to compute the time of twilight). This is the angle the Earth must turn from sunrise to noon, or from noon to sunset:

                sin(h) - sin(lat)*sin(Decl)
    cos(LHA) = -----------------------------
                   cos(lat) * cos(Decl)
If cos(LHA) is less than -1.0, then the Sun is always above our altitude limit. If we were computing rise/set times, the Sun is then aboute the horizon continuously; we have Midnight Sun. Or, if we computed a twilight, then the sky never gets dark (a good example is Stockholm, Sweden, at midsummer midnight: the Sun then only reaches about 7 degrees below the horizon: there will be civil twilight, but never nautical or astronomical twilight, at midsummer in Stockholm).

If cos(LHA) is greater than +1.0, then the Sun is always below our altitude limit. One example is midwinter in the arctics, when the Sun never gets above the horizon.

If cos(LHA) is between +1.0 and -1.0, then we take the arccos to find LHA. Convert from degrees to hours by dividing by 15.0

Now, if we add LHA to UT_Sun_in_south, we get the time of sunset. If we subtract LHA from UT_Sun_in_south, we get the time of sunrise.

Finally, we convert UT to our local time.

3. Higher accuracy: iteration

The method outlined above only gives an approximate value of the Sun's rise/set times. The error rarely exceeds one or two minutes, but at high latitudes, when the Midnight Sun soon will start or just has ended, the errors may be much larger. If you want higher accuracy, you must then iterate, and you must do a separate iteration for sunrise and sunset:

a) Compute sunrise or sunset as above, with one exception: to convert LHA from degrees to hours, divide by 15.04107 instead of 15.0 (this accounts for the difference between the solar day and the sidereal day. You should only use 15.04107 if you intend to iterate; if you don't want to iterate, use 15.0 as before since that will give an approximate correction for the Earth's orbital motion during the day).

b) Re-do the computation but compute the Sun's RA and Decl, and also GMST0, for the moment of sunrise or sunset last computed.

c) Iterate b) until the computed sunrise or sunset no longer changes significantly. Usually 2 iterations are enough, in rare cases 3 or 4 iterations may be needed.

d) Make sure you iterate towards the sunrise or sunset you want to compute, and not a sunrise or sunset one day earlier or later. If the computed rise or set time is, say, -0.5 hours local time, this means that it really happens at 23:30 the day before. If you get a value exceeding 24 hours local time, it means it happens the day after. If this is what you want, fine, otherwise add or subtract 24 hours. This only becomes a problem when there soon will be, or just has been, Midnight Sun.

e) Above the arctic circle, there are occasionally two sunrises, or two sunsets, during the same calendar day. Also there are days when the Sun only sets, or only rises, or neither rises nor sets. Pay attention to this if you don't want to miss any sunrise or sunset in your computations.

f) If you compute twilight instead of rise/set times, e) applies to the "twilight arctic circle". The normal arctic circle is situated at 66.7 deg latitude N and S (65.9 deg if one accounts for atmospheric refraction and the size of the solar disk). The "twilight arctic circle" is situated 6, 12, 15 or 18 deg closer to the equator, i.e. at latitude 60.7, 54.7, 51.7 or 48.7 degrees, depending on which twilight you're computing.

4. Computing the Moon's rise/set times.

This is really done the same way as the Sun's rise/set times, the only difference being that you should compute the RA and Decl for the Moon and not for the Sun. However, the Moon moves quickly and its rise/set times may change one or even two hours from one day to the next. If you don't iterate the Moon's rise/set times, you may get results which are in error by up to an hour, or more.

Another thing to consider is the lunar parallax, which affects the Moon's rise/set time by several minutes or more. One way to deal with the lunar parallax is to always use the Moon's topocentric RA and Decl. Another, simpler, way is to use the Moon's geocentric RA and Decl and instead adjust h, the rise/set altitude, by decreasing it by m_par, the lunar parallax. If you want to compute rise/set times for the Moon's upper limb rather than the center of the Moon's disk, you also need to compute m_sd, the semi-diameter or apparent radius of the Moon's disk in the sky. Note that the Moon's upper limb may for some lunar phases and circumstances be on the dark part of the Moon's disk

Thus you choose your h for Moon rise/set computation like this:

h = -m_par: Center of Moon's disk touches a mathematical horizon
h = -(m_par+m_sd): Moon's upper limb touches a mathematical horizon
h = -0.583 degrees - m_par: Center of Moon's disk touches the horizon; atmospheric refraction accounted for
h = -0.583 degrees - (m_par+m_sd): Moon's upper limb touches the horizon; atmospheric refraction accounted for

Yet another thing to consider: the Sun is always in the south near 12:00 local time, but the Moon may be in the south at any time of the day (or night). This means you must pay more attention that you're really iterating towards the rise or set time you want, and not some rise/set time one day earlier, or later.

Since the Moon rises and sets on the average 50 minutes later each day, there usually will be one day each month when the Moon never rises, and another day when it never sets. You must have this in mind when iterating your rise/set times, otherwise your program may easily get caught into an infinite loop when it tries to force e.g. a rise time between 00:00 and 24:00 local time on a day when the Moon never rises.

At high latitudes the Moon occasionally rises, or sets, twice on a single calendar day. This may happen above the "lunar arctic circle", which moves between 61.5 and 71.9 deg latitude during the 18-year period of the motion of the lunar nodes. You may want to pay attention to this.

Yes, computing the Moon's rise/set times is unfortunately messy, much due to its quick orbital motion around the Earth.

5. Computing rise/set times for other celestial bodies.

This is done the same way as for the Sun, with some differences:

a) Compute the RA and Decl for that body instead of for the Sun. If the body is a star, get its RA and Decl from a suitable star catalog.

b) GMST0 is still needed, so you should compute the Sun's mean longitude.

c) Always use 15.04107 instead of 15.0 when converting LHA from degrees to hours.

Since the planets move much slower than the Moon, and the stars hardly move at all, one need not iterate. If one wants high accuracy, one may find it worthwhile to iterate the rise/set times for Mercury, Venus and Mars (these are the planets that move most quickly).