Remove all dates in a range over multiple years

Viewed 589

Problem:

I have a multi-year dataset where I want to remove a range of dates (e.g. May 1 - August 31) across all years. I want to keep dates from April 30 to September 1 across all years.

Example of data:

dat <- data.frame(
  "Date" = c("2000-08-01","2000-11-02","2001-08-03","2001-11-04","2002-06-05","2002-02-06","2000-08-07","2000-02-08","2001-06-09","2001-11-10"),
  "Type" = c("A", "B", "C", "B", "C", "B", "A", "A", "C", "B"),
  "Num" = c(8,6,5,6.5,5,5.5,6,7,4,3)
)
dat

What I've tried:

I created an object with the dates for May 1 across all years, and using a for loop to remove the number of days following that until August 31. I know this is an extremely roundabout way, so I'm wondering if there's an easier solution as this is a rather large dataset.

dates_start <- as.Date(c("2000-05-01", "2001-05-01", "2002-05-01"))

for(i in 1:length(dates_start)){
  dat <- dat[!(as.Date(dat$Date) >= (dates_start[i] + 123)),]
}

Edit:

I plan to run this filter/removal multiple times to obtain different datasets, and in some cases, I want to remove dates in the middle of the month (e.g. April 15 to August 16), so just removing certain months would not work here.

3 Answers

You can create a date dynamically to remove :

library(dplyr)
library(lubridate)

start <- '04-15'
end <- '08-16'

dat %>% 
  mutate(Date = as.Date(Date), 
         year = year(Date)) %>%
  filter(!(Date >= ymd(paste(year, start, sep = '-')) & 
          Date <= ymd(paste(year, end, sep = '-'))))


#       Date Type Num year
#1 2000-11-02    B 6.0 2000
#2 2001-11-04    B 6.5 2001
#3 2002-02-06    B 5.5 2002
#4 2000-02-08    A 7.0 2000
#5 2001-11-10    B 3.0 2001

Does this work:

> library(dplyr)
> library(lubridate)
> dat$Date <- ymd(dat$Date)
> dat %>% filter(!month(Date) %in% 5:8)
        Date Type Num
1 2000-11-02    B 6.0
2 2001-11-04    B 6.5
3 2002-02-06    B 5.5
4 2000-02-08    A 7.0
5 2001-11-10    B 3.0
> 

As your date is a character you can extract the month with sub and then subset using this month number.

x <- as.integer(sub("\\d+-(\\d+)-\\d+", "\\1", dat$Date))
#x <- as.integer(format(as.Date(dat$Date), "%m")) #Alternative using Date
dat[x<5L | x>8L,]
#         Date Type Num
#2  2000-11-02    B 6.0
#4  2001-11-04    B 6.5
#6  2002-02-06    B 5.5
#8  2000-02-08    A 7.0
#10 2001-11-10    B 3.0

And for ranges also with days - where days lower than 10 need to have a leading 0:

x <- as.integer(sub("\\d+-(\\d+)-(\\d+)", "\\1\\2", dat$Date))
dat[x<501L | x>831L,]

Or paste the year to the month - which can cause problems for 29 February:

x <- format(as.Date(dat$Date), "%Y")
dat[as.Date(dat$Date) < as.Date(paste0(x,"-05-01")) |
    as.Date(dat$Date) > as.Date(paste0(x,"-08-31")),]

Or:

x <- as.Date(paste0("2000-", format(as.Date(dat$Date), "%m-%d")))
dat[x<as.Date("2000-05-01") | x>as.Date("2000-08-31"),]
Related