简体   繁体   中英

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?

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)

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

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)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM