r - 以 r 计算黎巴嫩的昼夜持续时间
问题描述
我有来自上一个问题的数据:
dat = structure(list(
start_time = structure(c(1431096404, 1431107312, 1431124632, 1431163956, 1431170210, 1431180438, 1431225936, 1431431610, 1431434550, 1431450416, 1431457208),
class = c("POSIXct", "POSIXt"), tzone = "America/Chicago"),
end_time = structure(c(1431104384, 1431119732, 1431126312, 1431168936, 1431179030, 1431193878, 1431240696, 1431432150, 1431447870, 1431455096, 1431465728),
class = c("POSIXct", "POSIXt"), tzone = "America/Chicago")),
row.names = c(NA, -11L),
class = "data.frame")
下面的函数就是答案。我的问题是如何编辑下面的函数来计算黎巴嫩而不是芝加哥的昼夜持续时间(以分钟为单位)。所以功能是:
library(lubridate)
library(tidyverse)
library(suncalc)
calc_in_oneday <- function(st, ed, lon = 0, lat = 0) {
sunlight_times <- getSunlightTimes(as.Date(st), lat = lat, lon = lon)
sunset <- sunlight_times$sunset
sunrise <- sunlight_times$sunrise
sec_night <- sec_day <- 0
if(st > sunset | ed<=sunrise) { # when the period includes the night only
sec_night <- difftime(ed, st, units = "secs")
} else if(st > sunrise & ed<=sunset) { # when the period includes the daytime only
sec_day <- difftime(ed, st, units = "secs")
} else { # when things are bit more complicated
if (st<=sunrise) { # if "start" is before sunrise time until sunrise will be added to night
sec_night <- sec_night + difftime(sunrise, st, units = "secs")
} else {
# if otherwise time until sunset will be added to daytime
# in this condition "end" will come after sunset (otherwise the second condition above will be satisfied)
sec_day <- sec_day + difftime(sunset, st, units = "secs")
}
if (ed<=sunset) { # The same logic
sec_day <- sec_day + difftime(ed, sunrise, units = "secs")
} else {
sec_night <- sec_night + difftime(ed, sunset, units = "secs")
}
if(st <= sunrise & ed > sunset) { # above will not add the entire daytime when "start" before sunrise and "end" after sunset
sec_day <- sec_day + difftime(sunset, sunrise, units = "secs")
}
}
sec_night <- unclass(sec_night)
sec_day <- unclass(sec_day)
attr(sec_day, "units") <- NULL
attr(sec_night, "units") <- NULL
return(list(sec_day = sec_day, sec_night = sec_night))
}
嵌套条件很复杂。我相信这是正确的,但请自行检查。
多日
使用上面的功能,处理多天的检查。该函数的作用是检查开始日期和结束日期是否相同,如果不相同,则计算到第一个日期结束的昼夜时间,然后将开始时间滑动到第二天的开始时间。(编辑:开始/结束时间的 tzone)。
calc_day_night <- function(st, ed, lon = 0, lat = 0) {
attr(st, "tzone") <- "UTC"
attr(ed, "tzone") <- "UTC"
sec_night <- sec_day <- 0
while(as.Date(st) != as.Date(ed)) {
tmp_ed <- as.Date(st) + days(1)
day_night_oneday <- calc_in_oneday(st, tmp_ed, lon, lat)
sec_night <- sec_night + day_night_oneday$sec_night
sec_day <- sec_day + day_night_oneday$sec_day
st <- tmp_ed
}
day_night_oneday <- calc_in_oneday(st, ed, lon, lat)
sec_night <- sec_night + day_night_oneday$sec_night
sec_day <- sec_day + day_night_oneday$sec_day
return(list(sec_day = sec_day, sec_night = sec_night))
}
测试使用测试数据,结果如下所示:
dat %>%
rowwise() %>%
mutate(temp = list(calc_day_night(start_time, end_time, lat = 41, lon = -85))) %>%
mutate(sec_day = temp$sec_day) %>%
mutate(sec_night = temp$sec_night) %>%
mutate(min_day = round(sec_day / 60)) %>%
mutate(min_night = round(sec_night / 60)) %>%
select(-matches("sec")) %>%
select(-temp)