-1

I would like to get the last day of the month from a year/month variable that is formated as integer YYYYMM.

yearmonth <- c(seq(202001,202012), 
            seq(202101,202112))

The output I am looking for is below. For instance, the last day of Feb/2020 was 29 (2020 was a leap year) whereas the last day of Feb/2021 was 28.

last <- c(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 
          31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

Ideally I would like to use the lubridate package.

U13-Forward
  • 69,221
  • 14
  • 89
  • 114
PaulaSpinola
  • 531
  • 2
  • 10

5 Answers5

2

Base R:

Try using:

day(as.Date(cut(as.Date(paste0(yearmonth, "01"), format = "%Y%m%d") + 32, 'month')) - 1)

Output:

31 29 31 30 31 30 31 31 30 31 30 31 31 28 31 30 31 30 31 31 30 31 30 31

Explanation:

This adds 32 days to all dates and uses the cut function to cut it by month (get the first day of each month). The after that, it subtracts 1 from the dates, which will give the last day of the original month

U13-Forward
  • 69,221
  • 14
  • 89
  • 114
1

Update:

Please notice akrun's comment, where we can use the truncated argument of th ymd() function to declare the number of formats that can be truncated:

days_in_month(ymd(yearmonth, truncated = 1))

First answer:

Here is a lubridate solution:

  1. construct date element such as year, month and day
  2. use make_date() to get a date class
  3. Then use days_in_month() function from lubridate
library(lubridate)

my_year <- substr(yearmonth,1,4)
my_month <- as.integer(substr(yearmonth,5,6))
my_day <- rep(1, length(my_year))


days_in_month(make_date(my_year, my_month, my_day))

# you can wrape around `unname` to get vector without names

Output:

Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb Mar Apr May Jun Jul 
 31  29  31  30  31  30  31  31  30  31  30  31  31  28  31  30  31  30  31 
Aug Sep Oct Nov Dec 
 31  30  31  30  31

# without names:

unname(days_in_month(make_date(my_year, my_month, my_day)))
[1] 31 29 31 30 31 30 31 31 30 31 30 31 31 28 31 30 31 30 31 31 30 31 30 31
TarJae
  • 72,363
  • 6
  • 19
  • 66
0

Using zoo's as.yearmon -

yearmonth |> 
  as.character() |>
  zoo::as.yearmon('%Y%m') |>
  as.Date(frac = 1) |>
  format('%d')

#[1] "31" "29" "31" "30" "31" "30" "31" "31" "30" "31" "30" "31" "31" "28"
#[15] "31" "30" "31" "30" "31" "31" "30" "31" "30" "31"

Using lubridate's ceiling_date function.

library(lubridate)
format(ceiling_date(ymd(paste0(yearmonth, '01')), 'month') - 1, '%d')
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
0

Using lubridate, I add one month to the first day of each provided month, and then I subtract one day. This date should be the last day of your months.

yearmonth <- c(seq(202001,202012), 
               seq(202101,202112))
yearmonthday <- as.Date(paste0(yearmonth, "01"), format = "%Y%m%d")

library(lubridate)
last <- as.numeric(format(yearmonthday + months(1) - days(1), format = "%d"))
last
Leonardo Hansa
  • 334
  • 3
  • 8
0

Using lurbidate:

library(lubridate)

day(ceiling_date(as.Date(paste0(yearmonth,'01'), format = '%Y%m%d'), unit = 'month') - 1)
 [1] 31 29 31 30 31 30 31 31 30 31 30 31 31 28 31 30 31 30 31 31 30 31 30 31
Karthik S
  • 11,348
  • 2
  • 11
  • 25