vinchinzu
vinchinzu

Reputation: 614

Count the number of Fridays or Mondays in Month in R

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?

Upvotes: 10

Views: 3389

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269624

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.

Upvotes: 12

TheComeOnMan
TheComeOnMan

Reputation: 12875

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)

Upvotes: 2

Dirk is no longer here
Dirk is no longer here

Reputation: 368241

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.

Upvotes: 2

Related Questions