Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count the number of Fridays or Mondays in Month in R

Tags:

r

lubridate

I would like a function that counts the number of specific days per month..

i.e.. Nov '13 -> 5 fridays.. while Dec'13 would return 4 Fridays..

Is there an elegant function that would return this?

library(lubridate)

num_days <- function(date){
x <- as.Date(date)  
start = floor_date(x, "month")
count = days_in_month(x)

d = wday(start) 
sol = ifelse(d > 4, 5, 4) #estimate that is the first day of the month is after Thu or Fri then the week will have 5 Fridays
sol
}

num_days("2013-08-01")
num_days(today())

What would be a better way to do this?

like image 713
vinchinzu Avatar asked Nov 11 '13 18:11

vinchinzu


3 Answers

1) Here d is the input, a Date class object, e.g. d <- Sys.Date(). The result gives the number of Fridays in the year/month that contains d. Replace 5 with 1 to get the number of Mondays:

first <- as.Date(cut(d, "month"))
last <- as.Date(cut(first + 31, "month")) - 1
sum(format(seq(first, last, "day"), "%w") == 5)

2) Alternately replace the last line with the following line. Here, the first term is the number of Fridays from the Epoch to the next Friday on or after the first of the next month and the second term is the number of Fridays from the Epoch to the next Friday on or after the first of d's month. Again, we replace all 5's with 1's to get the count of Mondays.

ceiling(as.numeric(last + 1 - 5 + 4) / 7) - ceiling(as.numeric(first - 5 + 4) / 7)

The second solution is slightly longer (although it has the same number of lines) but it has the advantage of being vectorized, i.e. d could be a vector of dates.

UPDATE: Added second solution.

like image 101
G. Grothendieck Avatar answered Sep 23 '22 10:09

G. Grothendieck


There are a number of ways to do it. Here is one:

countFridays <- function(y, m) { 
    fr <- as.Date(paste(y, m, "01", sep="-")) 
    to <- fr + 31       
    dt <- seq(fr, to, by="1 day")      
    df <- data.frame(date=dt, mon=as.POSIXlt(dt)$mon, wday=as.POSIXlt(dt)$wday)  
    df <- subset(df, df$wday==5 & df$mon==df[1,"mon"])         
    return(nrow(df))     
}

It creates the first of the months, and a day in the next months.

It then creates a data frame of month index (on a 0 to 11 range, but we only use this for comparison) and weekday.

We then subset to a) be in the same month and b) on a Friday. That is your result set, and we return the number of rows as your anwser.

Note that this only uses base R code.

like image 2
Dirk Eddelbuettel Avatar answered Sep 24 '22 10:09

Dirk Eddelbuettel


Without using lubridate -

#arguments to pass to function:
whichweekday <- 5
whichmonth <- 11
whichyear <- 2013

#function code:    
firstday <- as.Date(paste('01',whichmonth,whichyear,sep="-"),'%d-%m-%Y')
lastday <- if(whichmonth == 12) { '31-12-2013' } else {seq(as.Date(firstday,'%d-%m-%Y'), length=2, by="1 month")[2]-1}
sum(
  strftime(
seq.Date(
  from = firstday,
  to = lastday,
  by = "day"),
'%w'
) == whichweekday)
like image 2
TheComeOnMan Avatar answered Sep 22 '22 10:09

TheComeOnMan