# Is the shortest day duration constant?

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?

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

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

Zooming in on just one of those, it fluctuates.

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

The situation is reversed 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 = (
'solstice_day_length',
'solstice_day_length_dev',
'solstice_night_length',
'solstice_night_length_dev')

_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) :
matplotlib.pyplot.figure(self.figure_title())
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)
matplotlib.pyplot.title(self.plot_title())
matplotlib.pyplot.ylabel(self.ylabel())
matplotlib.pyplot.xlabel('Year')
matplotlib.pyplot.legend()
if self.show :
matplotlib.pyplot.show()
if self.save :
matplotlib.pyplot.savefig(
self.figure_title()+'_'+tag+'.png', dpi=200)
matplotlib.pyplot.close()

if __name__ == "__main__" :
years =  list(range(start_year,end_year+1))
show = False
save = True
matplotlib.style.use('seaborn-colorblind')
lon = 0
for tag, latitudes in [
('m60', [-60]),
('60',[60]),
('20',[20]),
('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.

• 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. – barrycarter Feb 7 '18 at 15:05
• @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). – David Hammen Feb 7 '18 at 17:30

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.

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
matplotlib.style.use("ggplot")
plt.plot(years, longest_nights, "-o")
plt.ylabel("Deviation from the mean, sec")
plt.xlabel("Year")
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')
#plt.savefig("solstice.png")
plt.show()

• 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. – David Hammen Dec 23 '17 at 3:55
• 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. – uhoh Dec 23 '17 at 4:21
• @davidhammen What is the cyclical variation due to? – DYZ Dec 23 '17 at 6:49
• @DYZ - The 18.6 lunar nodal cycle. See my answer. – David Hammen Dec 23 '17 at 17:08
• @DavidHammen I had a scaling issue, indeed (forgot to convert days to seconds). – 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.

• 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. – DYZ Dec 22 '17 at 21:43
• Yes, and I've answered that question. Edit, in case it was not clear. – James K Dec 22 '17 at 21:47