我想根据R中的开始时间和结束时间来计算白天和黑夜的分钟数。为了简化问题,我假设日出时间总是6点,日落时间总是6点,不论时区和位置如何。
以下是一些示例数据:
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")
它看起来像下面的数据框:
start_time end_time
1 2015-05-08 09:46:44 2015-05-08 11:59:44
2 2015-05-08 12:48:32 2015-05-08 16:15:32
3 2015-05-08 17:37:12 2015-05-08 18:05:12
4 2015-05-09 04:32:36 2015-05-09 05:55:36
5 2015-05-09 06:16:50 2015-05-09 08:43:50
6 2015-05-09 09:07:18 2015-05-09 12:51:18
7 2015-05-09 21:45:36 2015-05-10 01:51:36
8 2015-05-12 06:53:30 2015-05-12 07:02:30
9 2015-05-12 07:42:30 2015-05-12 11:24:30
10 2015-05-12 12:06:56 2015-05-12 13:24:56
11 2015-05-12 14:00:08 2015-05-12 16:22:08
我想添加两列minutes_day
和minutes_night
。 minutes_day
是该特定时段在白天(早上6点至下午6点)的分钟数,而minutes_night
是该特定时段在夜晚(下午6点至早上6点)的分钟数。第二天)。所以我想要的data.frame如下:
start_time end_time minutes_day minutes_night
1 2015-05-08 09:46:44 2015-05-08 11:59:44 133 0
2 2015-05-08 12:48:32 2015-05-08 16:15:32 207 0
3 2015-05-08 17:37:12 2015-05-08 18:05:12 23 5
4 2015-05-09 04:32:36 2015-05-09 05:55:36 0 83
5 2015-05-09 06:16:50 2015-05-09 08:43:50 147 0
6 2015-05-09 09:07:18 2015-05-09 12:51:18 224 0
7 2015-05-09 21:45:36 2015-05-10 01:51:36 0 246
8 2015-05-12 06:53:30 2015-05-12 07:02:30 9 0
9 2015-05-12 07:42:30 2015-05-12 11:24:30 222 0
10 2015-05-12 12:06:56 2015-05-12 13:24:56 78 0
11 2015-05-12 14:00:08 2015-05-12 16:22:08 142 0
由于start_time
和end_time
之间的某些日期不同,这个问题对我来说变得非常棘手。
有人在这个问题上有线索吗?谢谢!
答案 0 :(得分:1)
library(lubridate)
library(dplyr)
此函数创建从start_time
到end_time
的分钟序列,提取结果时间的小时数,将它们分隔为白天和黑夜,并获取最早时间与最新时间之间的时差白天和晚上。
get_minutes <- function(start_time, end_time) {
mins_in_range <- seq(start_time, end_time, by = "mins")
h_between <- hour(mins_in_range)
hours_day <- mins_in_range[h_between >= 6 &
h_between < 18]
hours_night <- mins_in_range[h_between < 6 |
h_between >= 18]
minutes_day <- tryCatch(as.numeric(difftime(max(hours_day),
min(hours_day),
units = "mins")),
warning = function(w) {
0
})
minutes_night <- tryCatch(as.numeric(difftime(max(hours_night),
min(hours_night),
units = "mins")),
warning = function(w) {
0
})
return(list(minutes_day = minutes_day,
minutes_night = minutes_night))
}
然后,您可以遍历每行数据,应用函数(返回list
列)并将列表分隔为列(借助data.table
和rbindlist
:
dat %>%
rowwise() %>%
mutate(temp = list(get_minutes(start_time, end_time))) %>%
cbind(data.table::rbindlist(.$temp)) %>%
select(-temp)
最终结果如下:
start_time end_time minutes_day minutes_night
1: 2015-05-08 09:46:44 2015-05-08 11:59:44 133 0
2: 2015-05-08 12:48:32 2015-05-08 16:15:32 207 0
3: 2015-05-08 17:37:12 2015-05-08 18:05:12 22 5
4: 2015-05-09 04:32:36 2015-05-09 05:55:36 0 83
5: 2015-05-09 06:16:50 2015-05-09 08:43:50 147 0
6: 2015-05-09 09:07:18 2015-05-09 12:51:18 224 0
7: 2015-05-09 21:45:36 2015-05-10 01:51:36 0 246
8: 2015-05-12 06:53:30 2015-05-12 07:02:30 9 0
9: 2015-05-12 07:42:30 2015-05-12 11:24:30 222 0
10: 2015-05-12 12:06:56 2015-05-12 13:24:56 78 0
11: 2015-05-12 14:00:08 2015-05-12 16:22:08 142 0
答案 1 :(得分:1)
它需要很多编码,但是我认为这可以完成工作。实际上,它每天从suncalc
包中获取实际的日落和日出时间。
我会尽快对其进行注释。
当开始日期和结束日期相同时,此功能以秒为单位计算昼夜。为了获得确切的日出和日落时间,您需要提供位置的纬度和经度。
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))
}
嵌套条件很复杂。我相信这是正确的,但请您自己检查。
使用以上功能,处理多日内的支票。该功能的作用是检查开始日期和结束日期,如果不相同,请计算直到第一个日期结束的白天/夜晚时间,然后将开始时间滑动到第二天的开始。 (编辑:开始/结束时间的时区)。
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)
## Source: local data frame [11 x 4]
## Groups: <by row>
##
## # A tibble: 11 x 4
## start_time end_time min_day min_night
## <dttm> <dttm> <dbl> <dbl>
## 1 2015-05-08 09:46:44 2015-05-08 11:59:44 133 0
## 2 2015-05-08 12:48:32 2015-05-08 16:15:32 207 0
## 3 2015-05-08 17:37:12 2015-05-08 18:05:12 28 0
## 4 2015-05-09 04:32:36 2015-05-09 05:55:36 26 57
## 5 2015-05-09 06:16:50 2015-05-09 08:43:50 147 0
## 6 2015-05-09 09:07:18 2015-05-09 12:51:18 224 0
## 7 2015-05-09 21:45:36 2015-05-10 01:51:36 0 246
## 8 2015-05-12 06:53:30 2015-05-12 07:02:30 9 0
## 9 2015-05-12 07:42:30 2015-05-12 11:24:30 222 0
## 10 2015-05-12 12:06:56 2015-05-12 13:24:56 78 0
## 11 2015-05-12 14:00:08 2015-05-12 16:22:08 142 0
我搜索了芝加哥的经纬度,并使用了这些值。如您所见,对于某些记录,结果有所变化(例如,由于芝加哥的黎明是在夏季初,所以记录#4并不完全是夜晚。