Day length calculation
The winter solstice has been on many minds lately. The days are about to start getting longer … but just how fast will they do that?
This post provides R code that calculates and graphs day length and its
variation, using uniroot() to find sunrises and sunsets as indicated by solar
altitude, as computed with the oce function sunAngle().
The day of the solstice is indicated with vertical lines. All times are in UTC,
which is the conventional system for scientific work and the one required by
sunAngle().
The first step in making the graph shown below is to load the oce library
and create a function that measures day length by finding sunrise and sunset
times. Note that uniroot(), which is used to find times of zero solar
altitude, needs lower and upper limits on t, and these are calculated by
looking back and then forward a half-day. This works well for application to
Halifax, but in other timezones other offsets would be needed. Interested
readers might want to devise a method based on the longitude, which can be
transformed into a timezone.

Code
library(oce)
if (!interactive()) png("2013-12-21-day-length.png")
daylength <- function(t, lon = -63.60, lat = 44.65) {
t <- as.numeric(t)
alt <- function(t) {
sunAngle(t, longitude = lon, latitude = lat)$altitude
}
rise <- uniroot(alt, lower = t - 86400 / 2, upper = t)$root
set <- uniroot(alt, lower = t, upper = t + 86400 / 2)$root
set - rise
}
# Compute day length for December, 2013.
t0 <- as.POSIXct("2013-12-01 12:00:00", tz = "UTC")
t <- seq.POSIXt(t0, by = "1 day", length.out = 1 * 31)
dayLength <- unlist(lapply(t, daylength))
# Set up to plot two panels, with narrowed margins.
par(mfrow = c(2, 1), mar = c(3, 3, 1, 1), mgp = c(2, 0.7, 0))
# daylength in the top panel
plot(t, dayLength / 3600,
type = "o", pch = 20,
xlab = "", ylab = "Day length (hours)"
)
grid()
solstice <- as.POSIXct("2013-12-21", tz = "UTC")
abline(v = solstice + c(0, 86400))
# daylenfth difference in bottom panel
plot(t[-1], diff(dayLength),
type = "o", pch = 20,
xlab = "Day in 2013", ylab = "Seconds gained per day"
)
grid()
abline(v = solstice + c(0, 86400))