No código abaixo, estou tentando completar uma sequência de datas. Minha data de inÃcio é 31 de maio e a data de término é 31 de agosto. Quando eu seq()
por mês abaixo, você verá que junho de 2023 é pulado, mas julho de 2023 aparece duas vezes (primeiro e último dia do mês). Quero sequenciar por mês para que cada mês apareça na sequência entre as duas datas. Como posso fazer isso?
library(tidyverse)
df1 <- data.frame(id = "1",
startdate = as.Date( "2023-05-31"),
enddate = as.Date("2024-08-31")) %>%
mutate(date_duration = startdate,
enddate = ceiling_date(enddate, "month") -1 ) %>%
complete(date_duration = seq(startdate, enddate, by = "month"))
Editar segundo exemplo
Usando o código postado por Jon abaixo, funciona para meu primeiro exemplo. No entanto, se a data de inÃcio começar no primeiro dia do mês, recebo meses repetidos novamente. É possÃvel contornar isso?
df1 <- data.frame(id = c("1","2"),
startdate = as.Date( c("2023-05-31", "2023-01-01")),
enddate = as.Date(c("2024-08-31", "2023-03-15")),
date_duration = as.Date( c("2023-05-31", "2023-01-01"))
) %>%
group_by(id) %>%
complete(date_duration = seq(ceiling_date(startdate, "month"),
ceiling_date(enddate, "month"),
by = "month") - 1)
Esta é uma deficiência da
seq.Date
função base, que não funciona como você pode esperar para os últimos dias do mês. (Presumo que isso seja porque os meses têm durações diferentes e, portanto, é ambÃguo o que o usuário quer e como conseguir isso de forma simples. Na prática, presume-se que você está procurando a data que seria onde o 31º seria se existisse, então abaixo mostra 2024-07-01 onde você esperaria 2024-06-30.)Mas funciona como você espera com os primeiros dias do mês, então você pode modificar assim:
Você pode considerar algo como a linha abaixo, que arredonda para o próximo mês (que será sequenciado conforme o esperado), então você pode voltar um dia. Isso cuida da situação em que você pode fornecer 2024-02-28, que não é o último dia do mês, mas pode ser fornecido por um usuário esperando que seja.
Também adiciono
id
,startdate
, eenddate
conforme eles existem em seus dados. Não tenho certeza se você quer isso ou não, mas parece útil para mim.Resultado
EDITAR:
Ou, se quisermos apenas "uma linha por mês", poderÃamos aplicar floor_date nas colunas de definição primeiro, algo como: (desleixado porque não sei quais linhas você precisa manter no formato original)