Search code examples
rdatedatetimeposixctdate-sunrise

Adding information on day/dusk/night/dawn for tracking data in R


I have a dataset with tracking data containing Datetime, Latitude and Longitude variables for several months which looks like this:

> start <- as.POSIXct("2018-08-01 00:00:00", format="%Y-%m-%d %H:%M:%S", tz="UTC")
> datetime <- seq(from = start, length.out = 2880, by = "5 mins")
> lat<-rep(seq(from=50, to= 30, length.out = 10), each=288)
> lon<-rep(seq(from=110, to= 70, length.out = 10), each=288)
> data<-cbind.data.frame(datetime, lat, lon)
> head(data)
             datetime lat lon
1 2018-08-01 00:00:00  50 110
2 2018-08-01 00:05:00  50 110
3 2018-08-01 00:10:00  50 110
4 2018-08-01 00:15:00  50 110
5 2018-08-01 00:20:00  50 110
6 2018-08-01 00:25:00  50 110

I want to add a new column with information on the period of the day, i.e. day, dusk, night or dawn, based on information from getSunlightTimes:

> data$date<-as.Date(data$datetime)
> sun<-getSunlightTimes(data=data, tz="UTC", keep=c("sunrise","sunset","night","nightEnd"))
> head(sun)
        date lat lon             sunrise              sunset               night
1 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
2 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
3 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
4 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
5 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
6 2018-08-01  50 110 2018-07-31 21:09:50 2018-08-01 12:25:18 2018-08-01 15:01:56
             nightEnd
1 2018-07-31 18:33:13
2 2018-07-31 18:33:13
3 2018-07-31 18:33:13
4 2018-07-31 18:33:13
5 2018-07-31 18:33:13
6 2018-07-31 18:33:13

So dusk would correspond to datetime values between sunset and night, dawn between nightEnd and sunrise, day between sunrise and sunset and night between night and nightEnd.

I've tried:

> data$period<-rep(" ", length.out=nrow(data))
> data$period[which(data$datetime>sun$sunrise & data$datetime<sun$sunset)]<-"day"
> data$period[which(data$datetime>sun$sunset & data$datetime<sun$night)]<-"dusk"
> data$period[which(data$datetime>sun$nightEnd & data$datetime<sun$sunrise)]<-"dawn"
> data$period[which(data$period==" ")]<-"night"

but this causes problems at the transition between days. Anyone have any suggestions?

Kind regards


Solution

  • A tidyverse option that - like the solution by Roman Luštrik - uses a left_join.

    library(dplyr)
    library(lubridate)
    
    df1 %>%
      mutate(date = date(datetime)) %>%
      left_join(df2) %>%
      distinct() %>%
      mutate(period = case_when(datetime %within% interval(sunset, night) ~ 'dusk',
                                datetime %within% interval(nightEnd, sunrise) ~ 'dawn',
                                datetime %within% interval(sunrise, sunset) ~ 'day',
                                datetime %within% interval(night, nightEnd) ~ 'night')) %>%
      select(datetime, lat, lon, period)
    
    # # A tibble: 6 x 4
    #   datetime              lat   lon period
    #   <dttm>              <dbl> <dbl> <chr> 
    # 1 2018-08-01 00:00:00    50   110 day   
    # 2 2018-08-01 00:05:00    50   110 day   
    # 3 2018-08-01 00:10:00    50   110 day   
    # 4 2018-08-01 00:15:00    50   110 day   
    # 5 2018-08-01 00:20:00    50   110 day   
    # 6 2018-08-01 00:25:00    50   110 day
    

    Data

    df1 <- structure(list(datetime = structure(c(1533081600, 1533081900, 
    1533082200, 1533082500, 1533082800, 1533083100), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC"), lat = c(50, 50, 50, 50, 50, 50), lon = c(110, 
    110, 110, 110, 110, 110)), row.names = c(NA, -6L), class = c("tbl_df", 
    "tbl", "data.frame"))
    
    df2 <- structure(list(date = structure(c(17744, 17744, 17744, 17744, 
    17744, 17744), class = "Date"), lat = c(50, 50, 50, 50, 50, 50
    ), lon = c(110, 110, 110, 110, 110, 110), sunrise = structure(c(1533071390, 
    1533071390, 1533071390, 1533071390, 1533071390, 1533071390), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC"), sunset = structure(c(1533126318, 1533126318, 
    1533126318, 1533126318, 1533126318, 1533126318), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC"), night = structure(c(1533135716, 1533135716, 
    1533135716, 1533135716, 1533135716, 1533135716), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC"), nightEnd = structure(c(1533061993, 
    1533061993, 1533061993, 1533061993, 1533061993, 1533061993), class = c("POSIXct", 
    "POSIXt"), tzone = "UTC")), row.names = c(NA, -6L), class = c("tbl_df", 
    "tbl", "data.frame"))