I have a data frame of dates and the day of the week
> head(data)
day weekday
1 2016-01-01 Friday
4 2016-01-04 Monday
5 2016-01-05 Tuesday
require(data.table)
lfom<-function(d){
x<-seq(min(d),max(d),by=1)
fri<-which(wday(x)==6)
mend<-which(mday(x)==1)-1
d %in% x[fri[findInterval(mend,fri)]]
}
ldom<-function(d){
x<-seq(min(d),max(d),by=1)
mend<-which(mday(x)==1)-1
d %in% x[mend]
}
data <-data.frame(
day = seq(as.Date("2014-01-01"), as.Date("2016-05-10"), "day"),
weekday = weekdays(seq(as.Date("2014-01-01"), as.Date("2016-05-10"), "day"))
)
excludeDays <- c("Saturday", "Sunday")
data <- data.table(subset(data, !weekdays(data$day) %in% excludeDays)) #exclude weekend
data$lfom<-lfom(data$day)
data$ldom<-ldom(data$day)
library(lubridate)
library(dplyr)
data%>%
mutate(year = year(day),month= month(day)) %>%
group_by(year, month) %>%
mutate(LastDayInMonth = max(day)==day)%>%
arrange(day) %>%
ungroup() %>%
group_by(year, month, weekday) %>%
mutate(LastWeekInMonth = row_number() == n(),
LastFriayInMonth = weekday =="Freitag" & LastWeekInMonth == 1) %>%
ungroup()%>%
select(day, weekday, LastDayInMonth,LastFriayInMonth)
Same excerpt as above (%>% filter(LastDayInMonth | LastFriayInMonth == TRUE):
Source: local data frame [8 x 4]
day weekday LastDayInMonth LastFriayInMonth
(date) (fctr) (lgl) (lgl)
1 2016-01-29 Freitag TRUE TRUE
2 2016-02-26 Freitag FALSE TRUE
3 2016-02-29 Montag TRUE FALSE
4 2016-03-25 Freitag FALSE TRUE
5 2016-03-31 Donnerstag TRUE FALSE
6 2016-04-29 Freitag TRUE TRUE
7 2016-05-06 Freitag FALSE TRUE
8 2016-05-10 Dienstag TRUE FALSE
With the additional clarification and following the comment by @eminik the code below
library(data.table)
setDT(data)
data[, LastDayInMonth := day == max(day), by = .(year(day), month(day))]
data[, LastFridayInMonth := weekday == "Friday" & day == max(day),
by = .(year(day), month(day), weekdays(day))]
produces:
# show results (only relevant rows)
data[LastDayInMonth | LastFridayInMonth == TRUE]
day weekday LastDayInMonth LastFridayInMonth
1: 2016-01-29 Friday TRUE TRUE
2: 2016-02-26 Friday FALSE TRUE
3: 2016-02-29 Monday TRUE FALSE
4: 2016-03-25 Friday FALSE TRUE
5: 2016-03-31 Thursday TRUE FALSE
6: 2016-04-29 Friday TRUE TRUE
7: 2016-05-06 Friday FALSE TRUE
8: 2016-05-10 Tuesday TRUE FALSE
Edit: Code modified to account for change of years as requested by OP.
Note: weekdays
returns a character vector of names in the locale in use. Therefore, the code only works if you are in an English locale. Otherwise, you may have to use Sys.setlocale(category = "LC_ALL", locale = "English")
before.
I'm using lubridate
for date calculations, but since you have missing days in between, I use lead()
function from dplyr
to find the next day (row) in the data.
library(lubridate)
library(dplyr)
my.data <- tbl_df(data)
my.data <- my.data %>%
# First last day of month
# get the next day in the data
mutate(next.day = lead(day)) %>%
# it's month is different
mutate(LastDayInMonth = ifelse(month(day) != month(next.day), T, F)) %>%
# Now Last Friday
mutate(LastFridayInMonth =
ifelse( (wday(day) == 6) & # It's a Friday
# Check the month of next Friday, different
(month(lead(day, 5)) != month(day)
| is.na(lead(day, 5))), T, F))