Home > OS >  How to use cut function on dates
How to use cut function on dates

Time:11-26

I have the following two dates:

dates <- c("2019-02-01",   "2019-06-30")

I want to create the following bins from above two dates:

2019-05-30, 2019-04-30, 2019-03-31, 2019-02-28 

I used cut function along with seq,

dt <- as.Date(dates)

cut(seq(dt[1], dt[2], by = "month"), "month")

but this does not produce correct results.

Could you please shed some light on the use of cut function on dates?

CodePudding user response:

There is no need for cut here:

library(lubridate)
dates <- c("2019-02-01", "2019-06-30")
seq(min(ymd(dates)), max(ymd(dates)), by = "months") - 1
#> [1] "2019-01-31" "2019-02-28" "2019-03-31" "2019-04-30" "2019-05-31"

Created on 2021-11-25 by the reprex package (v2.0.1)

CodePudding user response:

We assume that what is wanted is all end of months between but not including the 2 dates in dates. In the question dates[1] is the beginning of the month and dates[2] is the end of the month but we do not assume that although if we did it might be simplified. We have produced descending series below but usually in R one uses ascending.

The first approach below uses a monthly sequence and cut and the second approach below uses a daily sequence.

No packages are used.

1) We define a first of the month function, fom, which given a Date or character date gives the Date of the first of the month using cut. Then we calculate monthly dates between the first of the months of the two dates, convert those to end of the month and then remove any dates that are not strictly between the dates in dates.

fom <- function(x) as.Date(cut(as.Date(x), "month"))

s <- seq(fom(dates[2]), fom(dates[1]), "-1 month")
ss <- fom(fom(s)   32) - 1
ss[ss > dates[1] & ss < dates[2]]
## [1] "2019-05-31" "2019-04-30" "2019-03-31" "2019-02-28"

2) Another approach is to compute a daily sequence between the two elements of dates after converting to Date class and then only keep those for which the next day has a different month and is between the dates in dates. This does not use cut.

dt <- as.Date(dates)
s <- seq(dt[2], dt[1], "-1 day")
s[as.POSIXlt(s)$mon != as.POSIXlt(s 1)$mon & s > dt[1] & s < dt[2]]
## [1] "2019-05-31" "2019-04-30" "2019-03-31" "2019-02-28"
  • Related