Stupid_Intern
Stupid_Intern

Reputation: 3450

Get 2nd and 4th Saturday of Month

d = seq(as.Date("2018-01-01"),Sys.Date(),by='day')
saturdayList = d[weekdays(d)=='Saturday']

How to get the 2nd and 4th saturday of a month from above list of Saturday dates?

Upvotes: 2

Views: 421

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 270065

1) This calculates a vector of 2nd and 4th Saturdays directly from d although we could replace d with saturdayList and it would still work.

Define nextsat, based on nextfri in the zoo quickref vignette, which gives the next Saturday on or after the input date for each element of the input vector. Then for each element of d find the first of the month, apply nextsat to give the first Saturday of the month and add 7 to get the second Saturday of each month. Add 14 to get the 4th Saturday and sort into a single vector. No packages are used.

nextsat <- function(x) 7 * ceiling(as.numeric(x-6+4) / 7) + 
  as.Date(6-4, origin = "1970-01-01")

sat2 <- unique(nextsat(as.Date(cut(d, "month")))) + 7
sort(c(sat2, sat2 + 14))

giving:

 [1] "2018-01-13" "2018-01-20" "2018-02-10" "2018-02-17" "2018-03-10"
 [6] "2018-03-17" "2018-04-14" "2018-04-21" "2018-05-12" "2018-05-19"
[11] "2018-06-09" "2018-06-16" "2018-07-14" "2018-07-21" "2018-08-11"
[16] "2018-08-18" "2018-09-08" "2018-09-15" "2018-10-13" "2018-10-20"
[21] "2018-11-10" "2018-11-17" "2018-12-08" "2018-12-15" "2019-01-12"
[26] "2019-01-19" "2019-02-09" "2019-02-16" "2019-03-09" "2019-03-16"

2) This computes a vector satno giving the number of each Saturday within its month and then picks off the second and fourth. This also does not use any packages.

satno <- ave(as.numeric(saturdayList), cut(saturdayList, "month"), FUN = seq_along)
saturdayList[satno %in% c(2, 4)]

Upvotes: 1

Wimpel
Wimpel

Reputation: 27782

data.table solution

The solution is slower (on the sample data), than the 'lapply-solution' from docendo discimus. However, it is very flexible, and will alsoperform quite well on larger data-sets.

library(data.table)
#build a data.table out of the vector
DT <- data.table(date = d)
#group by month, select the second and 4 row where wday == 7 (i.e. Saturday)
DT[ DT[ , .I[wday(date) == 7][c(2,4)], by = .(month(date)) ]$V1 ]

output

# date
# 1: 2018-01-13
# 2: 2018-01-27
# 3: 2018-02-10
# 4: 2018-02-24
# 5: 2018-03-10
# 6: 2018-03-24
# 7: 2018-04-14
# 8: 2018-04-28
# 9: 2018-05-12
# 10: 2018-05-26
# 11: 2018-06-09
# 12: 2018-06-23
# 13: 2018-07-14
# 14: 2018-07-28
# 15: 2018-08-11
# 16: 2018-08-25
# 17: 2018-09-08
# 18: 2018-09-22
# 19: 2018-10-13
# 20: 2018-10-27
# 21: 2018-11-10
# 22: 2018-11-24
# 23: 2018-12-08
# 24: 2018-12-22
# date

Upvotes: 1

talat
talat

Reputation: 70336

You can split the vector into a list and extract the 2nd and 4th element per month:

lapply(split(saturdayList, format(saturdayList, "%Y-%m")), `[`, c(2, 4))
# $`2018-01`
# [1] "2018-01-13" "2018-01-27"
# 
# $`2018-02`
# [1] "2018-02-10" "2018-02-24"
# 
# $`2018-03`
# [1] "2018-03-10" "2018-03-24"
# 
# $`2018-04`
# [1] "2018-04-14" "2018-04-28"
# ...

Without NA's:

lapply(split(saturdayList, format(saturdayList, "%Y-%m")), function(x)
       na.omit(x[c(2,4)]))

Assumptions:

  • The input is ordered by date (as in the example)
  • The input is a complete sequence without missing saturdays (as in the example)

Upvotes: 3

Related Questions