Last month, the Senate passed a bill intended to end the jump forward / jump backward era of Daylight Savings Time, and align on a year-round implementation of the summer “daylight saved” hours.
Besides showing that at least something can pass the Senate with bipartisan support, this bill gives hope for everyone who struggles to adjust their sleep cycles that an end may finally be in sight!
It’s important to note that there is healthy debate over whether or not Permanent Daylight Savings time is better or worse than adopting Permanent Standard Time… Permanent Daylight means that the sun will rise and set an hour later in the day, which certain people prefer, while others would rather preserve morning light.
However, I view either as an improvement over the current time-change regime we are in, and encourage the House and President Biden to pass the Senate’s bill into law!
Inspiration for this Post
Shortly following the news in the Senate, the Washington Post released an amazing map (previewable and linked in the Tweet below) showing what impact this proposal might have on sunrise times. In particular, they call out that a number of notherly areas in the US might see sunrises as late as 9:00 - 9:30 in the morning at the peak of winter.
How permanent daylight saving time would change sunrise and sunset timeshttps://t.co/0FTAMAlfIu
— The Washington Post (@washingtonpost) March 17, 2022
I was so struck by the “time gradient” running across the states in this map, that I knew I had to try to recreate the Post’s work on my own.
In addition, I had two other ideas for how to potentially improve the visuals:
- Show Standard Time and Permanent Daylight Time side-by-side, so that viewers have built-in context that they can use to inform their understanding of the changes
- Build a second map of sunset times, in addition to sunrise, to show the benefit of longer evenings in all these same geographies
Mapping Sunrise and Sunset
These maps are very high resolution, so don’t be afraid to open them in a new tab and really zoom in! Note that they show the distribution of sunrise and sunset times by county across the United States as of the 2022 Winter Solstice - the shortest day of the year.
Comparing Sunrise Times with Permanent Daylight Savings Against Standard Time
Comparing Sunset Times with Permanent Daylight Savings Against Standard Time
Code Reference: Building the Maps
Given that part of this effort was done solely for the fun of recreating the WaPo map, I wanted to share a rough overview of the map-making process for those who are curious, or interested in making similar maps in the future!
Get US Counties
library(usmap)
counties <- us_map(regions = "counties")
Get Centroids for each County
For simplicity’s sake, we can just take the center point of each US County from this amazing table on Wikipedia: Table of United States Counties. We’ll use this set of coordinates later to look up sunrise and sunset times.
library(readr)
fips_centroids <- read_csv("fips_centroids.csv")
Get Time Zones for each County
library(countytimezones)
# GET THE LOCAL TIME ZONE OF EACH COUNTY (FIPS)
fips_tz <- calc_local_time(
date_time = "2022-06-21 12:00",
fips = fips_centroids$fips
) %>%
select("local_tz")
fips_df <- cbind(fips_centroids, fips_tz)
Compute Sunrise and Sunset Times for Each County and Each Month
library(tibble)
library(lubridate)
# STORE LIST OF RESULTS IN HERE
fips_date_sun <- tibble(
date = character(),
fips = character(),
sunrise = character(),
sunset = character()
)
# THIS ITERATES OVER ALL MONTHS OF THE YEAR, WHICH IS MORE THAN WHAT IS NEEDED
for (i in 1:12) {
date <- as.Date(paste("2022-", i, "-21", sep = ""))
# THIS LOOPS OVER ALL COUNTIES IN THE fips_df
for (row in 1:nrow(fips_df)) {
fips <- fips_df[row, "fips"]
lat <- as.numeric(fips_df[row, "lat"])
lon <- as.numeric(fips_df[row, "lon"])
tz <- fips_df[row, "local_tz"]
# FETCH SUNRISE AND SUNSET TIMES FOR THAT COUNTY CENTROID AND DATE
temp <- getSunlightTimes(
date = date,
lat = lat,
lon = lon,
keep = c("sunrise", "sunset"),
tz = tz
) %>%
mutate(
fips = fips # TAG THE COUNTY WITH THE FIPS CODE
) %>%
mutate(
date = as.character(date),
sunrise = as.character(sunrise),
sunset = as.character(sunset)
) %>%
select("date", "fips", "sunrise", "sunset")
fips_date_sun <- fips_date_sun %>% add_row(temp)
}
}
fips_date_sun <- fips_date_sun %>%
mutate(
sunset = ymd_hms(sunset),
sunset_hour = hour(sunset),
sunset_minute = minute(sunset),
sunrise = ymd_hms(sunrise),
sunrise_hour = hour(sunrise),
sunrise_minute = minute(sunrise)
)
Clean and Bucket Sunrise and Sunset Times
require(lubridate)
winter_solstice <- fips_date_sun %>%
filter(date == "2022-12-21") %>%
filter(fips != '02185') %>%
filter(fips != '46113')
# THERE ARE A FEW FIPS THAT HAVE CHANGED, THIS MANUALLY FIXES A FEW OF THEM IN OUR DATA
winter_solstice[nrow(winter_solstice) + 1,] <- list('2022-12-21', '02185', ymd_hms('2022-12-21 06:45:42'), ymd_hms('2022-12-21 06:45:42'), 15, 47, 12, 4)
winter_solstice[nrow(winter_solstice) + 1,] <- list('2022-12-21', '46102', ymd_hms('2022-12-21 07:20:48'), ymd_hms('2022-12-21 16:18:28'), 16, 18, 7, 20)
winter_solstice[nrow(winter_solstice) + 1,] <- list('2022-12-21', '02158', ymd_hms('2022-12-21 06:45:42'), ymd_hms('2022-12-21 06:45:42'), 15, 47, 12, 4)
# BUCKETIZE THE SUNRISE/SET TIMES FOR EASIER MAPPING
winter_solstice <- winter_solstice %>%
mutate(
adj_sunset_hour = sunset_hour + 1,
adj_sunrise_hour = sunrise_hour + 1
) %>%
mutate(
sunset_bucket = case_when(
sunset_hour < 15 ~ '< 3:30',
sunset_hour <= 15 & sunset_minute <= 30 ~ '< 3:30',
sunset_hour < 16 ~ '3:30 - 4:00',
sunset_hour <= 16 & sunset_minute <= 30 ~ '4:00 - 4:30',
sunset_hour < 17 ~ '4:30 - 5:00',
sunset_hour <= 17 & sunset_minute <= 30 ~ '5:00 - 5:30',
sunset_hour < 18 ~ '5:30 - 6:00',
sunset_hour <= 18 & sunset_minute <= 30 ~ '6:00 - 6:30',
sunset_hour < 19 ~ '> 6:30',
sunset_hour >= 19 ~ '> 6:30'
) ,
adj_sunset_bucket = case_when(
adj_sunset_hour < 15 ~ '< 3:30',
adj_sunset_hour <= 15 & sunset_minute <= 30 ~ '< 3:30',
adj_sunset_hour < 16 ~ '3:30 - 4:00',
adj_sunset_hour <= 16 & sunset_minute <= 30 ~ '4:00 - 4:30',
adj_sunset_hour < 17 ~ '4:30 - 5:00',
adj_sunset_hour <= 17 & sunset_minute <= 30 ~ '5:00 - 5:30',
adj_sunset_hour < 18 ~ '5:30 - 6:00',
adj_sunset_hour <= 18 & sunset_minute <= 30 ~ '6:00 - 6:30',
adj_sunset_hour < 19 ~ '> 6:30',
adj_sunset_hour >= 19 ~ '> 6:30'
),
sunrise_bucket = case_when(
sunrise_hour < 7 ~ '< 7:00',
sunrise_hour <= 7 & sunrise_minute <= 30 ~ '7:00 - 7:30',
sunrise_hour < 8 ~ '7:30 - 8:00',
sunrise_hour <= 8 & sunrise_minute <= 30 ~ '8:00 - 8:30',
sunrise_hour < 9 ~ '8:30 - 9:00',
sunrise_hour <= 9 & sunrise_minute <= 30 ~ '9:00 - 9:30',
sunrise_hour < 10 ~ '9:30 - 10:00',
sunrise_hour >= 10 ~ '> 10:00'
),
adj_sunrise_bucket = case_when(
adj_sunrise_hour < 7 ~ '< 7:00',
adj_sunrise_hour <= 7 & sunrise_minute <= 30 ~ '7:00 - 7:30',
adj_sunrise_hour < 8 ~ '7:30 - 8:00',
adj_sunrise_hour <= 8 & sunrise_minute <= 30 ~ '8:00 - 8:30',
adj_sunrise_hour < 9 ~ '8:30 - 9:00',
adj_sunrise_hour <= 9 & sunrise_minute <= 30 ~ '9:00 - 9:30',
adj_sunrise_hour < 10 ~ '9:30 - 10:00',
adj_sunrise_hour >= 10 ~ '> 10:00'
)
)
Build Map Visualization
library(reshape2)
library(viridis)
# CAPTURE SUNRISE TIMES FOR BOTH REGULAR AND DST
m_sunrise <- winter_solstice %>%
select(fips, sunrise_bucket, adj_sunrise_bucket) %>%
melt(id.vars = c("fips"), measure.vars = c("sunrise_bucket", "adj_sunrise_bucket"))
# MANUALLY ORDER THE SUNRISE TIMES AS FACTORS
m_sunrise$value <- factor(m_sunrise$value, levels = c("< 7:00", "7:00 - 7:30", "7:30 - 8:00", "8:00 - 8:30", "8:30 - 9:00", "9:00 - 9:30", "9:30 - 10:00", "> 10:00"))
# RE-LABEL THE FACET VARIABLES
sunrise_names <- as_labeller(c(`sunrise_bucket` = "Standard Time", `adj_sunrise_bucket` = "Permanent Daylight Savings"))
plot_usmap(
data = m_sunrise,
values = "value",
size = 0.1
) +
facet_wrap(
facets = vars(variable),
labeller = sunrise_names
) +
scale_fill_viridis_d(
option = "C",
name = "Sunrise Time (AM)",
direction = -1,
guide = guide_legend(reverse=TRUE)
) +
theme_void() +
theme(
strip.text = element_text(face = "bold"),
strip.text.x = element_text(margin=margin(b=5)),
plot.title = element_text(size = 20, face = "bold"),
plot.subtitle = element_text(size = 12, margin=margin(b=5, t = 5)),
plot.caption = element_text(colour = "grey60", margin=margin(b=5, t = 2)),
legend.position = "right"
) +
labs(
x = "",
y = "",
title = "Permanent Daylight Savings Exchanges Darker Mornings for Lighter Evenings",
subtitle = "Permanent Daylight Savings Time would lead to surprisingly late sunrise times during the peak of winter, with most of the continental US experiencing sunrise\nduring the 8:00 - 9:00 am hour, rather than the current 7:00 - 8:00 am hour",
caption = "Times show sunrise on the Winter Solstice (Dec 21, 2022), computed for the centroid of each county\nconormclaughlin.net"
)