Is the exact duration of the shortest day of a year (at the winter solstice in the northern hemisphere) always the same, for given latitude and longitude, or does it fluctuate? If it does, what is the range?

  • $\begingroup$ Well...in the southern hemisphere, it's the longest day of the year. $\endgroup$
    – BillDOe
    Dec 22 '17 at 20:58

By looking at the link provided by James K, I was able to write a Python 3 script that calculates the duration of the longest night for a predefined location (Boston, MA) for 160 years. The script uses the PyEphem module. The longest night becomes shorter by ~72 msec per year, and its length also oscillates with the period of ~19 years.

enter image description here

Here's the script that I used:

import ephem
import matplotlib.pyplot as plt
import matplotlib
import numpy as np

location = ephem.Observer()
location.lat, location.lon = '42.3601', '-71.0589'

years = range(1900, 2060)
longest_nights = []
for year in years:
    location.date = ephem.next_winter_solstice('{}-12-12'.format(year))
    sunset = location.next_setting(ephem.Sun())
    sunrise = location.next_rising(ephem.Sun())
    if sunrise < sunset: # Look at the night before!
        location.date -= 1       
        sunset = location.next_setting(ephem.Sun())
    longest_nights.append(sunrise - sunset)

longest_nights = np.array(longest_nights)
longest_nights = (longest_nights - longest_nights.mean()) * 24 * 3600 # In seconds

# Find the slope
xp = np.poly1d(np.polyfit(years, longest_nights, 1))
np_years = np.array(years).reshape(len(years), 1)

# Plot
plt.plot(years, longest_nights, "-o")
plt.ylabel("Deviation from the mean, sec")
plt.title("Duration of the longest night in a year in Boston")
plt.plot(years, xp(years), "-")
plt.arrow(2017, plt.ylim()[0], 0, plt.ylim()[1] - plt.ylim()[0], color='k')
  • 2
    $\begingroup$ Check your script. You have a scaling problem somewhere. You should be seeing much, much larger variations than that (e.g., 32.6 seconds variation for Dec 1911 versus Dec 2035 for Anchorage Alaska). That said, you are picking up two key attributes: An apparent secular trend due to the slow change in the Earth's axial tilt, and a cyclical variation of 18.6 years. $\endgroup$ Dec 23 '17 at 3:55
  • $\begingroup$ From time to time, when it is directly related to supporting an answer, a python script has been included in this site with out adverse effects. $\endgroup$
    – uhoh
    Dec 23 '17 at 4:21
  • 1
    $\begingroup$ @davidhammen What is the cyclical variation due to? $\endgroup$
    – DYZ
    Dec 23 '17 at 6:49
  • $\begingroup$ @DYZ - The 18.6 lunar nodal cycle. See my answer. $\endgroup$ Dec 23 '17 at 17:08
  • $\begingroup$ @DavidHammen I had a scaling issue, indeed (forgot to convert days to seconds). $\endgroup$
    – DYZ
    Dec 23 '17 at 18:31

It is not exactly the same each year. The exact moment of winter solstice is not at the same calendar date (because of leap days for example). In 2017 the solstice was at Dec 21 16:22, and in 2016 it was Dec 21 10:33. See also 22nd is shortest day in some places, but the 21st is shortest in other places. Can this be true?

So there is a little variation in the length of the shortest day, but the length of the day changes slowly at this time of year, so the range of variation is only a few seconds.

  • $\begingroup$ I am aware that the solstice does not fall on the same date and time. My question is about the duration of the shortest day, whenever that day happens. $\endgroup$
    – DYZ
    Dec 22 '17 at 21:43
  • $\begingroup$ Yes, and I've answered that question. Edit, in case it was not clear. $\endgroup$
    – James K
    Dec 22 '17 at 21:47

It appears to be quite constant when viewed on a coarse enough scale:

Lengths of the winter solstice night from 1900 to 2100, at 60, 40, and 20 degrees north latitude. The three curves look rather flat, with over 18 hours of darkness at 60 degrees, over 14.5 hours at 40 degrees, and a bit over 13 hours at 20 degrees.

Zooming in on just one of those, it fluctuates.

Lengths of the winter solstice night from 1900 to 2100, at 60 degrees north latitude. This curve exhibits a downward trend, plus an oscillation with a period of 18.6 years, plus shorter-term variations.

The variations at lower latitudes are similar but smaller in magnitude.

Deviations of the lengths of the winter solstice night from the mean from 1900 to 2100, at 60, 40, and 20 degrees north latitude.

The situation is reversed south of the equator.

Deviations of the lengths of the winter solstice night from the mean from 1900 to 2100, at 60, and 30 degrees north and south latitude. The length of the night on the December solstice has been increasing rather than decreasing south of the equator.

Python script used to create the above (python3, not python2):

import ephem
import matplotlib
import matplotlib.pyplot

start_year = 1900
end_year = 2100

class SolsticePlot :
    DayLength, DayLengthDev, NightLength, NightLengthDev = range(4)

    _figure_titles = (

    _plot_titles = (
        "December solstice day length",
        "December solstice day length deviation from mean",
        "December solstice night length",
        "December solstice night length deviation from mean")

    _ylabels = (
        "Day length (hours)",
        "Day length deviation (seconds)",
        "Night length (hours)",
        "Night length deviation (seconds)")

    def __init__ (self, ptype, show, save) :
        self.option = ptype
        self.show = show
        self.save = save

    def figure_title (self) :
        return self._figure_titles[self.option]

    def plot_title (self) :
        return self._plot_titles[self.option]

    def ylabel (self) :
        return self._ylabels[self.option]

    def use_day_length(self) :
        return self.option == self.DayLength or \
            self.option == self.DayLengthDev

    def use_deviations(self) :
        return self.option == self.DayLengthDev or \
            self.option == self.NightLengthDev

    def _next_interval(self, obs, sun) :
        obs.date = obs.next_transit(sun) # Noon
        sun.compute (obs)
        if self.use_day_length() :
            return obs.next_setting(sun) - obs.previous_rising(sun)
        else :
            return obs.next_rising(sun) - obs.next_setting(sun)

    def _extremal_length(self, year, lat, lon) :

        obs = ephem.Observer()
        obs.lat = str(lat)
        obs.lon = str(lon)

        sun = ephem.Sun()

        # Get day or night lengths in 6 day window about the solstice.
        solstice = ephem.next_solstice(42357+(year-2015)*365.25)
        ndays = 6
        obs.date = solstice-ndays/2
        sun.compute (obs)
        lengths = [24.0*self._next_interval(obs, sun) for _ in range(ndays)]

        # Find the shortest or longest, as appropriate.
        if (lat >= 0.0) == self.use_day_length() :
            index = min(range(ndays), key=lengths.__getitem__)
        else :
            index = max(range(ndays), key=lengths.__getitem__)
        if (index == 0) or (index == ndays-1) :
            raise RuntimeError("Can't find shortest day")

        return lengths[index]

    def ydata (self, years, lat, lon) :
        extrema = [self._extremal_length(y, lat, lon) for y in years]
        if self.use_deviations() :
            avg = sum(extrema) / len(extrema)
            return [3600*(x-avg) for x in extrema]
        else :
            return extrema

    def plot(self, years, latitudes, lon) :
        for ilat,lat in enumerate(latitudes) :
            color = "C{:d}".format(ilat+1)
            label = "{:d}\N{DEGREE SIGN} N".format(lat)
            matplotlib.pyplot.plot(years, self.ydata(years, lat, lon),
                color=color, linestyle='solid', marker='+', label=label)
        if self.show :
        if self.save :
                self.figure_title()+'_'+tag+'.png', dpi=200)

if __name__ == "__main__" :
    years =  list(range(start_year,end_year+1))
    show = False
    save = True
    lon = 0
    for tag, latitudes in [
        ('m60', [-60]),
        ('60_40_20', [60, 40, 20]),
        ('pm60_30',[60,30, -30, -60])] :
        for ptype in range(4) :
            SolsticePlot(ptype, show, save).plot(years, latitudes, lon)

Over the very long term (a hundred thousand of years or more), the Earth's rotation rate is getting slower. This is a true secular trend that will eventually result in increases in the lengths of both the day and the night on the day of the year with the least daylight of the year, regardless of other effects.

This very slow secular increase is counteracted or exacerbated by cyclical effects. One is the Earth's axial tilt. This varies cyclically, but with a period of 41000 years. Over the short term (hundreds of years is short in this context), the effects of changing axial tilt are much stronger than are the effects of the secular increase in the length of day. The Earth is currently in a phase where the axial tilt is decreasing. This makes the length of daylight increase on the "shortest day of the year", and hence makes the length of that longest night decrease.

A much shorter term cyclical effect results from the location of the Moon with respect to the Earth and Sun. The Earth and Moon together orbit the Sun. This means that when the Moon is above the plane of this orbit, the Earth will be slightly below, and vice versa. This subtly changes the lighting of the Earth. Where this occurs varies as the lunar node precesses over an 18.6 year period.

  • 1
    $\begingroup$ I'm not convinced that using a fixed longitude is the best approach here, because the time of the solstice will affect the length of night. Ideally, you'd compute the night length at the longitude where the solstice occurs at solar midnight. $\endgroup$
    – user21
    Feb 7 '18 at 15:05
  • $\begingroup$ @barrycarter - The question asked with regard to a given latitude and longitude, so that's what I answered. That said, I doubt that your suggestion will have much of an effect. You'll still see the 18.6 year cycle due to the precession of the lunar node, and you'll still see what appears to be a secular change (actually periodic, but with a period of 41000 years). $\endgroup$ Feb 7 '18 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.