<p>It appears to be quite constant when viewed on a coarse enough scale:</p>

<p><a href="https://i.sstatic.net/rVXap.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/rVXap.png" alt="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."></a></p>

<p>Zooming in on just one of those, it fluctuates.</p>

<p><a href="https://i.sstatic.net/ogxDy.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/ogxDy.png" alt="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."></a></p>

<p>The variations at lower latitudes are similar but smaller in magnitude.</p>

<p><a href="https://i.sstatic.net/IWQEF.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/IWQEF.png" alt="Deviations of the lengths of the winter solstice night from the mean from 1900 to 2100, at 60, 40, and 20 degrees north latitude."></a></p>

<p>The situation is reversed south of the equator.</p>

<p><a href="https://i.sstatic.net/7bXtg.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/7bXtg.png" alt="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."></a></p>

<p>Python script used to create the above (python3, not python2):</p>

<pre><code>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 &gt;= 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)
</code></pre>

<hr>

<p>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.</p>

<p>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.</p>

<p>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.</p>

CC BY-SA 3.0
2018-02-07T17:30:41.570Z
@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
CC BY-SA 3.0
2017-12-23T15:56:29.407Z
2017-12-23T17:04:39.070Z
2017-12-23T17:04:39.070Z
David Hammen
<p>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 <em>PyEphem</em> module. The longest night becomes shorter by ~72 msec per year, and its length also oscillates with the period of ~19 years.</p>

<p><a href="https://i.sstatic.net/HoAtr.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/HoAtr.png" alt="enter image description here"></a></p>

<p>Here's the script that I used:</p>

<pre><code>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 &lt; 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()
</code></pre>

CC BY-SA 3.0
2017-12-23T03:55:22.363Z
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
CC BY-SA 3.0
2017-12-23T04:21:53.457Z
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
CC BY-SA 3.0
2017-12-23T06:49:36.183Z
@davidhammen What is the cyclical variation due to?
DYZ
CC BY-SA 3.0
2017-12-23T17:08:59.927Z
@DYZ - The 18.6 lunar nodal cycle. See my answer.
David Hammen
CC BY-SA 3.0
2017-12-23T18:31:09.687Z
@DavidHammen I had a scaling issue, indeed (forgot to convert days to seconds).
DYZ
CC BY-SA 3.0
2017-12-22T22:33:07.597Z
2017-12-23T21:55:45.083Z
2017-12-23T21:55:45.083Z
DYZ
<p>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 <a href="https://astronomy.stackexchange.com/questions/12940/22nd-is-shortest-day-in-some-places-but-the-21st-is-shortest-in-other-places-c?rq=1">22nd is shortest day in some places, but the 21st is shortest in other places. Can this be true?</a></p>

<p>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.</p>

CC BY-SA 3.0
2017-12-22T21:43:59.607Z
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
CC BY-SA 3.0
2017-12-22T21:47:42.537Z
Yes, and I've answered that question. Edit, in case it was not clear.
James K
CC BY-SA 3.0
2017-12-22T21:37:05.287Z
2017-12-22T21:48:04.690Z
2017-12-22T21:48:04.690Z
James K
<p>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?</p>

CC BY-SA 3.0
2017-12-22T20:58:20.077Z
Well...in the southern hemisphere, it's the longest day of the year.
BillDOe
<orbit><earth>
Is the shortest day duration constant?
DYZ
# Is the shortest day duration constant?

(Asked by: username_0 on 2017-12-22)

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?

**Tags:** orbit, earth
> **Comments:**
> **username_1**: Well...in the southern hemisphere, it's the longest day of the year.  

---

## 3 answers

### Answer by username_2 on 2017-12-23. Score: 1 | Accepted answer

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.

> **Comments:**
> **username_2**: @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).  

---

### Answer by username_0 on 2017-12-22. Score: 3

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()

> **Comments:**
> **username_2**: 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.  
> **username_3**: 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.  
> **username_0**: @davidhammen What is the cyclical variation due to?  
> **username_2**: @DYZ - The 18.6 lunar nodal cycle. See my answer.  
> **username_0**: @DavidHammen I had a scaling issue, indeed (forgot to convert days to seconds).  

---

### Answer by username_4 on 2017-12-22. Score: 2

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?](https://astronomy.stackexchange.com/questions/12940/22nd-is-shortest-day-in-some-places-but-the-21st-is-shortest-in-other-places-c?rq=1)

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.

> **Comments:**
> **username_0**: 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.  
> **username_4**: Yes, and I've answered that question. Edit, in case it was not clear.  

---

