R: Finding out between which dates a certain action occurs
21:17 06 Dec 2025

I am working with the R programming language.

I have this dataset:

library(dplyr)
library(tidyr)
library(lubridate)

combined <- structure(list(country = c("Canada", "France", "Japan", "Brazil", 
"Canada", "France", "Japan", "Brazil", "Canada", "France", "Japan", 
"Brazil"), Red = c("yes", "no", "yes", "yes", "no", "yes", "no", 
"yes", "yes", "yes", "yes", "yes"), Blue = c("no", "yes", "yes", 
"no", "yes", "yes", "yes", "no", "yes", "no", "yes", "no"), Green = c("yes", 
"yes", "no", "yes", "no", "yes", "yes", "yes", "yes", "yes", 
"no", "yes"), time = c("2000-01-01", "2000-01-01", "2000-01-01", 
"2000-01-01", "2000-02-01", "2000-02-01", "2000-02-01", "2000-02-01", 
"2000-03-01", "2000-03-01", "2000-03-01", "2000-03-01")), class = "data.frame", row.names = c(NA, 
-12L))


country Red Blue Green       time
  Canada yes   no   yes 2000-01-01
  France  no  yes   yes 2000-01-01
   Japan yes  yes    no 2000-01-01
  Brazil yes   no   yes 2000-01-01
  Canada  no  yes    no 2000-02-01
  France yes  yes   yes 2000-02-01
   Japan  no  yes   yes 2000-02-01
  Brazil yes   no   yes 2000-02-01
  Canada yes  yes   yes 2000-03-01
  France yes   no   yes 2000-03-01
   Japan yes  yes    no 2000-03-01
  Brazil yes   no   yes 2000-03-01

I want to answer the following question: For each country, each color was held between which time frames?

My current approach is using 2 steps:

long_data <- combined %>%
    pivot_longer(
        cols = c(Red, Blue, Green),
        names_to = "color",
        values_to = "has_color"
    ) %>%
    mutate(time = as.Date(time)) %>%
    arrange(country, color, time)


    result <- long_data %>%
        filter(has_color == "yes") %>%
        group_by(country, color) %>%
        mutate(
            period_id = cumsum(c(1, diff(as.numeric(time)) > 31))
        ) %>%
        group_by(country, color, period_id) %>%
        summarise(
            date_start = min(time),
            date_end   = ceiling_date(max(time), "month") - days(1),
            .groups = "drop"
        ) %>%
        select(country, color, date_start, date_end)

> result
# A tibble: 14 × 4
   country color date_start date_end  
                
 1 Brazil  Green 2000-01-01 2000-03-31
 2 Brazil  Red   2000-01-01 2000-03-31
 3 Canada  Blue  2000-02-01 2000-03-31
 4 Canada  Green 2000-01-01 2000-01-31
 5 Canada  Green 2000-03-01 2000-03-31
 6 Canada  Red   2000-01-01 2000-01-31
 7 Canada  Red   2000-03-01 2000-03-31
 8 France  Blue  2000-01-01 2000-02-29
 9 France  Green 2000-01-01 2000-03-31
10 France  Red   2000-02-01 2000-03-31
11 Japan   Blue  2000-01-01 2000-03-31
12 Japan   Green 2000-02-01 2000-02-29
13 Japan   Red   2000-01-01 2000-01-31
14 Japan   Red   2000-03-01 2000-03-31

Is there a more straightforward way to solve this problem in a single step?

r