首页 > 解决方案 > 以 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) 

标签: r

解决方案


推荐阅读