From f21e3eb0585c4041deb7d37f6b4b7ddeac138f01 Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Sun, 19 Jun 2022 21:15:14 -0300 Subject: [PATCH 1/8] Changes to optimize getdate getnthday and getnthweekday have been rewritten. Now they are ref methods and make a unique with the table year_month. This change avoids duplicate calculations. --- R/getdate.R | 210 ++++++++++++++++++++++---------- tests/testthat/test-parsedate.R | 11 +- 2 files changed, 149 insertions(+), 72 deletions(-) diff --git a/R/getdate.R b/R/getdate.R index a09e574..6a9281f 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -55,24 +55,12 @@ getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { } n <- getnth_(tok[1]) if (tok[2] == "day") { - date_res <- lapply( - seq_len(NROW(ref$year_month)), - function(x) getnthday_(n, ref, cal, x) - ) - as.Date(unlist(date_res), origin = as.Date("1970-01-01")) + getnthday(ref, n, cal$dates.table, FALSE) } else if (tok[2] == "bizday") { - date_res <- lapply( - seq_len(NROW(ref$year_month)), - function(x) getnthday_(n, ref, cal, x, TRUE) - ) - as.Date(unlist(date_res), origin = as.Date("1970-01-01")) + getnthday(ref, n, cal$dates.table, TRUE) } else if (tok[2] %in% WEEKDAYS) { wday <- which(tok[2] == WEEKDAYS) - date_res <- lapply( - seq_len(NROW(ref$year_month)), - function(x) getnthweekday_(n, ref, cal, wday, x) - ) - as.Date(unlist(date_res), origin = as.Date("1970-01-01")) + getnthweekday(ref, n, cal$dates.table, wday) } else { stop("Invalid expr", expr) } @@ -109,46 +97,27 @@ ref <- function(x, ...) UseMethod("ref") ref.Date <- function(x, ym = c("month", "year"), ...) { ym <- match.arg(ym) - that <- if (ym == "month") { - list( - dates = x, - by_month = TRUE, - year_month = cbind(year = YEAR(x), month = MONTH(x)) - ) + if (ym == "month") { + ref_by_month(year = YEAR(x), month = MONTH(x)) } else { - list( - dates = x, - by_month = FALSE, - year_month = cbind(year = YEAR(x)) - ) + ref_by_year(year = YEAR(x)) } - structure(that, class = "ref") } ref.character <- function(x, ...) { - that <- if (all(grepl("^(\\d{4})-(\\d{2})$", x))) { + if (all(grepl("^(\\d{4})-(\\d{2})$", x))) { mx <- regmatches(x, regexec("^(\\d{4})-(\\d{2})$", x)) mx <- do.call(rbind, mx) - list( - by_month = TRUE, - year_month = cbind( - year = as.integer(mx[, 2]), - month = as.integer(mx[, 3]) - ) - ) + ref_by_month(as.integer(mx[, 2]), as.integer(mx[, 3])) } else if (all(grepl("^(\\d{4})$", x))) { mx <- regmatches(x, regexec("^(\\d{4})$", x)) mx <- do.call(rbind, mx) - list( - by_month = FALSE, - year_month = cbind(year = as.integer(mx[, 2])) - ) + ref_by_year(as.integer(mx[, 2])) } else if (all(grepl("^\\d{4}-\\d{2}-\\d{2}$", x))) { do.call(ref.Date, append(list(...), list(x = as.Date(x)))) } else { stop("Invalid character ref ", x) } - structure(that, class = "ref") } ref.numeric <- function(x, ...) { @@ -156,7 +125,26 @@ ref.numeric <- function(x, ...) { by_month = FALSE, year_month = cbind(year = x) ) - structure(that, class = "ref") + structure(that, class = c("ref", "by_year")) +} + +ref_by_year <- function(year) { + that <- list( + by_month = FALSE, + year_month = cbind(year = year) + ) + structure(that, class = c("ref", "by_year")) +} + +ref_by_month <- function(year, month) { + that <- list( + by_month = TRUE, + year_month = cbind( + year = year, + month = month + ) + ) + structure(that, class = c("ref", "by_month")) } MONTH <- function(x) as.integer(format(x, "%m")) @@ -185,34 +173,126 @@ getnth_ <- function(x) { ) } -getnthday_ <- function(pos, ref, cal, ref_pos = 1, use_bizday = FALSE) { - ix <- if (ref$by_month) { - ix_ <- cal$dates.table[, "month"] == ref$year_month[ref_pos, "month"] & - cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] - if (use_bizday) ix_ & cal$dates.table[, "is_bizday"] == 1 else ix_ - } else { - ix_ <- cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] - if (use_bizday) ix_ & cal$dates.table[, "is_bizday"] == 1 else ix_ +getnthday <- function(ref, ...) { + UseMethod("getnthday") +} + +getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { + ym_table <- unique(ref$year_month) + + date_res <- lapply( + seq_len(NROW(ym_table)), + function(x) { + month <- ym_table[x, "month"] + year <- ym_table[x, "year"] + ix <- cal_table[, "month"] == month & cal_table[, "year"] == year + ix <- if (use_bizday) ix & cal_table[, "is_bizday"] == 1 else ix + + sel_range <- cal_table[ix, ] + # pos < 0 == last --> NROW(selected_range) + pos <- if (pos < 0) NROW(sel_range) else pos + date <- unname(sel_range[pos, "dates"]) + + idx <- ref$year_month[, "year"] == year & ref$year_month[, "month"] == month + list(date = date, index = idx) + } + ) + + dates <- integer(NROW(ref$year_month)) + for (res in date_res) { + dates[res$index] <- res$date } - x <- cal$dates.table[ix, ] - pos <- if (pos < 0) NROW(x) else pos - res <- as.Date(x[pos, "dates"], origin = as.Date("1970-01-01")) - unname(res) + + as.Date(dates, origin = as.Date("1970-01-01")) } -getnthweekday_ <- function(pos, ref, cal, wday, ref_pos = 1) { - ix <- if (ref$by_month) { - ix_ <- cal$dates.table[, "month"] == ref$year_month[ref_pos, "month"] & - cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] - ix_ & cal$dates.table[, "weekday"] == wday - } else { - ix_ <- cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] - ix_ & cal$dates.table[, "weekday"] == wday +getnthday.by_year <- function(ref, pos, cal_table, use_bizday = FALSE) { + ym_table <- unique(ref$year_month) + + date_res <- lapply( + seq_len(NROW(ym_table)), + function(x) { + year <- ym_table[x, "year"] + ix <- cal_table[, "year"] == year + ix <- if (use_bizday) ix & cal_table[, "is_bizday"] == 1 else ix + + sel_range <- cal_table[ix, ] + # pos < 0 == last --> NROW(selected_range) + pos <- if (pos < 0) NROW(sel_range) else pos + date <- unname(sel_range[pos, "dates"]) + + idx <- ref$year_month[, "year"] == year + list(date = date, index = idx) + } + ) + + dates <- integer(NROW(ref$year_month)) + for (res in date_res) { + dates[res$index] <- res$date + } + + as.Date(dates, origin = as.Date("1970-01-01")) +} + +getnthweekday <- function(ref, ...) { + UseMethod("getnthweekday") +} + +getnthweekday.by_month <- function(ref, pos, cal_table, wday) { + ym_table <- unique(ref$year_month) + + date_res <- lapply( + seq_len(NROW(ym_table)), + function(x) { + month <- ym_table[x, "month"] + year <- ym_table[x, "year"] + ix <- cal_table[, "month"] == month & cal_table[, "year"] == year + ix <- ix & cal_table[, "weekday"] == wday + + sel_range <- cal_table[ix, ] + # pos < 0 == last --> NROW(selected_range) + pos <- if (pos < 0) NROW(sel_range) else pos + date <- unname(sel_range[pos, "dates"]) + + idx <- ref$year_month[, "year"] == year & ref$year_month[, "month"] == month + list(date = date, index = idx) + } + ) + + dates <- integer(NROW(ref$year_month)) + for (res in date_res) { + dates[res$index] <- res$date } - x <- cal$dates.table[ix, ] - pos <- if (pos < 0) NROW(x) else pos - res <- as.Date(x[pos, "dates"], origin = as.Date("1970-01-01")) - unname(res) + + as.Date(dates, origin = as.Date("1970-01-01")) +} + +getnthweekday.by_year <- function(ref, pos, cal_table, wday) { + ym_table <- unique(ref$year_month) + + date_res <- lapply( + seq_len(NROW(ym_table)), + function(x) { + year <- ym_table[x, "year"] + ix <- cal_table[, "year"] == year + ix <- ix & cal_table[, "weekday"] == wday + + sel_range <- cal_table[ix, ] + # pos < 0 == last --> NROW(selected_range) + pos <- if (pos < 0) NROW(sel_range) else pos + date <- unname(sel_range[pos, "dates"]) + + idx <- ref$year_month[, "year"] == year + list(date = date, index = idx) + } + ) + + dates <- integer(NROW(ref$year_month)) + for (res in date_res) { + dates[res$index] <- res$date + } + + as.Date(dates, origin = as.Date("1970-01-01")) } WEEKDAYS <- c("thu", "fri", "sat", "sun", "mon", "tue", "wed") \ No newline at end of file diff --git a/tests/testthat/test-parsedate.R b/tests/testthat/test-parsedate.R index 39b33c8..4578859 100644 --- a/tests/testthat/test-parsedate.R +++ b/tests/testthat/test-parsedate.R @@ -35,18 +35,15 @@ test_that("it should create a year-month reference", { expect_is(rrr, "ref") expect_true(rrr$by_month) expect_equal(rrr$year_month, cbind(year = 2018, month = 1)) - expect_equal(rrr$dates, as.Date("2018-01-01")) rrr <- ref(as.Date("2018-01-01"), "year") expect_is(rrr, "ref") expect_false(rrr$by_month) expect_equal(rrr$year_month, cbind(year = 2018)) - expect_equal(rrr$dates, as.Date("2018-01-01")) expect_error(ref(as.Date("2018-01-01"), "day")) rrr <- ref(c(as.Date("2018-01-01"), as.Date("2018-02-01")), "month") expect_is(rrr, "ref") expect_true(rrr$by_month) expect_equal(rrr$year_month, cbind(year = 2018, month = c(1, 2))) - expect_equal(rrr$dates, c(as.Date("2018-01-01"), as.Date("2018-02-01"))) rrr <- ref("2018-01") expect_is(rrr, "ref") expect_true(rrr$by_month) @@ -69,15 +66,15 @@ test_that("it should create a year-month reference", { test_that("it should get the nth day by the reference", { rrr <- ref(as.Date("2018-01-01"), "month") cal <- calendars()[["actual"]] - expect_equal(getnthday_(1, rrr, cal), as.Date("2018-01-01")) - expect_equal(getnthday_(-1, rrr, cal), as.Date("2018-01-31")) + expect_equal(getnthday(rrr, 1, cal$dates.table), as.Date("2018-01-01")) + expect_equal(getnthday(rrr, -1, cal$dates.table), as.Date("2018-01-31")) cal <- calendars()[["Brazil/ANBIMA"]] expect_equal( - getnthday_(1, rrr, cal, use_bizday = TRUE), + getnthday(rrr, 1, cal$dates.table, use_bizday = TRUE), as.Date("2018-01-02") ) expect_equal( - getnthday_(-1, rrr, cal, use_bizday = TRUE), + getnthday(rrr, -1, cal$dates.table, use_bizday = TRUE), as.Date("2018-01-31") ) }) \ No newline at end of file From 19abf218670efa5926895f182f66560964675c7b Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Sun, 19 Jun 2022 21:24:52 -0300 Subject: [PATCH 2/8] Renamed year_month to ref_table --- R/getbizdays.R | 8 ++++---- R/getdate.R | 30 +++++++++++++++--------------- tests/testthat/test-parsedate.R | 16 ++++++++-------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/R/getbizdays.R b/R/getbizdays.R index 394279e..b06be32 100644 --- a/R/getbizdays.R +++ b/R/getbizdays.R @@ -31,7 +31,7 @@ getbizdays <- function(ref, cal = bizdays.options$get("default.calendar")) { ref <- ref(ref) bizdays_ <- lapply( - seq_len(NROW(ref$year_month)), + seq_len(NROW(ref$ref_table)), function(x) count_bizdays_(ref, cal, x) ) unlist(bizdays_) @@ -39,10 +39,10 @@ getbizdays <- function(ref, cal = bizdays.options$get("default.calendar")) { count_bizdays_ <- function(ref, cal, ref_pos) { ix <- if (ref$by_month) { - cal$dates.table[, "month"] == ref$year_month[ref_pos, "month"] & - cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] + cal$dates.table[, "month"] == ref$ref_table[ref_pos, "month"] & + cal$dates.table[, "year"] == ref$ref_table[ref_pos, "year"] } else { - cal$dates.table[, "year"] == ref$year_month[ref_pos, "year"] + cal$dates.table[, "year"] == ref$ref_table[ref_pos, "year"] } sum(cal$dates.table[ix, "is_bizday"]) } \ No newline at end of file diff --git a/R/getdate.R b/R/getdate.R index 6a9281f..25457cc 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -123,7 +123,7 @@ ref.character <- function(x, ...) { ref.numeric <- function(x, ...) { that <- list( by_month = FALSE, - year_month = cbind(year = x) + ref_table = cbind(year = x) ) structure(that, class = c("ref", "by_year")) } @@ -131,7 +131,7 @@ ref.numeric <- function(x, ...) { ref_by_year <- function(year) { that <- list( by_month = FALSE, - year_month = cbind(year = year) + ref_table = cbind(year = year) ) structure(that, class = c("ref", "by_year")) } @@ -139,7 +139,7 @@ ref_by_year <- function(year) { ref_by_month <- function(year, month) { that <- list( by_month = TRUE, - year_month = cbind( + ref_table = cbind( year = year, month = month ) @@ -178,7 +178,7 @@ getnthday <- function(ref, ...) { } getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { - ym_table <- unique(ref$year_month) + ym_table <- unique(ref$ref_table) date_res <- lapply( seq_len(NROW(ym_table)), @@ -193,12 +193,12 @@ getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { pos <- if (pos < 0) NROW(sel_range) else pos date <- unname(sel_range[pos, "dates"]) - idx <- ref$year_month[, "year"] == year & ref$year_month[, "month"] == month + idx <- ref$ref_table[, "year"] == year & ref$ref_table[, "month"] == month list(date = date, index = idx) } ) - dates <- integer(NROW(ref$year_month)) + dates <- integer(NROW(ref$ref_table)) for (res in date_res) { dates[res$index] <- res$date } @@ -207,7 +207,7 @@ getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { } getnthday.by_year <- function(ref, pos, cal_table, use_bizday = FALSE) { - ym_table <- unique(ref$year_month) + ym_table <- unique(ref$ref_table) date_res <- lapply( seq_len(NROW(ym_table)), @@ -221,12 +221,12 @@ getnthday.by_year <- function(ref, pos, cal_table, use_bizday = FALSE) { pos <- if (pos < 0) NROW(sel_range) else pos date <- unname(sel_range[pos, "dates"]) - idx <- ref$year_month[, "year"] == year + idx <- ref$ref_table[, "year"] == year list(date = date, index = idx) } ) - dates <- integer(NROW(ref$year_month)) + dates <- integer(NROW(ref$ref_table)) for (res in date_res) { dates[res$index] <- res$date } @@ -239,7 +239,7 @@ getnthweekday <- function(ref, ...) { } getnthweekday.by_month <- function(ref, pos, cal_table, wday) { - ym_table <- unique(ref$year_month) + ym_table <- unique(ref$ref_table) date_res <- lapply( seq_len(NROW(ym_table)), @@ -254,12 +254,12 @@ getnthweekday.by_month <- function(ref, pos, cal_table, wday) { pos <- if (pos < 0) NROW(sel_range) else pos date <- unname(sel_range[pos, "dates"]) - idx <- ref$year_month[, "year"] == year & ref$year_month[, "month"] == month + idx <- ref$ref_table[, "year"] == year & ref$ref_table[, "month"] == month list(date = date, index = idx) } ) - dates <- integer(NROW(ref$year_month)) + dates <- integer(NROW(ref$ref_table)) for (res in date_res) { dates[res$index] <- res$date } @@ -268,7 +268,7 @@ getnthweekday.by_month <- function(ref, pos, cal_table, wday) { } getnthweekday.by_year <- function(ref, pos, cal_table, wday) { - ym_table <- unique(ref$year_month) + ym_table <- unique(ref$ref_table) date_res <- lapply( seq_len(NROW(ym_table)), @@ -282,12 +282,12 @@ getnthweekday.by_year <- function(ref, pos, cal_table, wday) { pos <- if (pos < 0) NROW(sel_range) else pos date <- unname(sel_range[pos, "dates"]) - idx <- ref$year_month[, "year"] == year + idx <- ref$ref_table[, "year"] == year list(date = date, index = idx) } ) - dates <- integer(NROW(ref$year_month)) + dates <- integer(NROW(ref$ref_table)) for (res in date_res) { dates[res$index] <- res$date } diff --git a/tests/testthat/test-parsedate.R b/tests/testthat/test-parsedate.R index 4578859..95b8ccf 100644 --- a/tests/testthat/test-parsedate.R +++ b/tests/testthat/test-parsedate.R @@ -34,33 +34,33 @@ test_that("it should create a year-month reference", { rrr <- ref(as.Date("2018-01-01"), "month") expect_is(rrr, "ref") expect_true(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018, month = 1)) + expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) rrr <- ref(as.Date("2018-01-01"), "year") expect_is(rrr, "ref") expect_false(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018)) + expect_equal(rrr$ref_table, cbind(year = 2018)) expect_error(ref(as.Date("2018-01-01"), "day")) rrr <- ref(c(as.Date("2018-01-01"), as.Date("2018-02-01")), "month") expect_is(rrr, "ref") expect_true(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018, month = c(1, 2))) + expect_equal(rrr$ref_table, cbind(year = 2018, month = c(1, 2))) rrr <- ref("2018-01") expect_is(rrr, "ref") expect_true(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018, month = 1)) + expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) rrr <- ref("2018") expect_is(rrr, "ref") expect_false(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018)) + expect_equal(rrr$ref_table, cbind(year = 2018)) rrr <- ref(2018) expect_is(rrr, "ref") expect_false(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018)) + expect_equal(rrr$ref_table, cbind(year = 2018)) rrr <- ref(2010:2018) - expect_equal(rrr$year_month, cbind(year = 2010:2018)) + expect_equal(rrr$ref_table, cbind(year = 2010:2018)) rrr <- ref("2018-01-01", ym = "month") expect_true(rrr$by_month) - expect_equal(rrr$year_month, cbind(year = 2018, month = 1)) + expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) }) test_that("it should get the nth day by the reference", { From 95b3dbe7fad99a51942a86e5bc87ee4566e80d49 Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Sun, 19 Jun 2022 22:45:19 -0300 Subject: [PATCH 3/8] Implemented getdate by days getdate use a single day as reference and it allows to call for the next day and last day (or bizday) according to that given day. ``` r getdate("next day", Sys.Date()) getdate("last day", Sys.Date()) getdate("next bizday", Sys.Date(), "Brazil/ANBIMA") getdate("last bizday", Sys.Date(), "Brazil/ANBIMA") ``` --- R/getdate.R | 48 +++++++++++++++++++------------- tests/testthat/test-getbizdays.R | 6 ++-- tests/testthat/test-getdate.R | 11 ++++++++ tests/testthat/test-parsedate.R | 40 ++++++++++++-------------- 4 files changed, 60 insertions(+), 45 deletions(-) diff --git a/R/getdate.R b/R/getdate.R index 25457cc..5310fcc 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -55,9 +55,9 @@ getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { } n <- getnth_(tok[1]) if (tok[2] == "day") { - getnthday(ref, n, cal$dates.table, FALSE) + getnthday(ref, n, cal, FALSE) } else if (tok[2] == "bizday") { - getnthday(ref, n, cal$dates.table, TRUE) + getnthday(ref, n, cal, TRUE) } else if (tok[2] %in% WEEKDAYS) { wday <- which(tok[2] == WEEKDAYS) getnthweekday(ref, n, cal$dates.table, wday) @@ -79,15 +79,9 @@ getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { #' Details) #' @param ... additional arguments #' -#' If a date (\code{character} or \code{Date}) is passed to \code{ref} it has to -#' specified whether the reference is to the month or the year of the given -#' date. This is set in the argument \code{ym} that accepts \code{month} -#' (default) or \code{year}. -#' #' @examples -#' ref(as.Date("2018-01-01"), "month") # refers to 2018-01 -#' ref("2018-01-01", "month") # refers to 2018-01 -#' ref("2018-01-01", "year") # refers to 2018 +#' ref(as.Date("2018-01-01")) # refers to 2018-01-01 +#' ref("2018-01-01") # refers to 2018-01-01 #' #' ref(c("2018-01", "2018-02")) # refers to 2018-01 and 2018-02 #' ref("2018") # refers to 2018 @@ -95,13 +89,8 @@ getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { #' @noRd ref <- function(x, ...) UseMethod("ref") -ref.Date <- function(x, ym = c("month", "year"), ...) { - ym <- match.arg(ym) - if (ym == "month") { - ref_by_month(year = YEAR(x), month = MONTH(x)) - } else { - ref_by_year(year = YEAR(x)) - } +ref.Date <- function(x, ...) { + ref_by_day(x) } ref.character <- function(x, ...) { @@ -114,7 +103,7 @@ ref.character <- function(x, ...) { mx <- do.call(rbind, mx) ref_by_year(as.integer(mx[, 2])) } else if (all(grepl("^\\d{4}-\\d{2}-\\d{2}$", x))) { - do.call(ref.Date, append(list(...), list(x = as.Date(x)))) + ref_by_day(as.Date(x)) } else { stop("Invalid character ref ", x) } @@ -147,6 +136,14 @@ ref_by_month <- function(year, month) { structure(that, class = c("ref", "by_month")) } +ref_by_day <- function(dates) { + that <- list( + by_month = FALSE, + dates = dates + ) + structure(that, class = c("ref", "by_day")) +} + MONTH <- function(x) as.integer(format(x, "%m")) YEAR <- function(x) as.integer(format(x, "%Y")) @@ -162,6 +159,7 @@ nth2int <- function(x) { getnth_ <- function(x) { switch(x, + `next` = 1, first = 1, second = 2, third = 3, @@ -177,8 +175,17 @@ getnthday <- function(ref, ...) { UseMethod("getnthday") } -getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { +getnthday.by_day <- function(ref, pos, cal, use_bizday = FALSE) { + if (use_bizday) { + add.bizdays(ref$dates, pos, cal) + } else { + add.bizdays(ref$dates, pos, "actual") + } +} + +getnthday.by_month <- function(ref, pos, cal, use_bizday = FALSE) { ym_table <- unique(ref$ref_table) + cal_table <- cal$dates.table date_res <- lapply( seq_len(NROW(ym_table)), @@ -206,8 +213,9 @@ getnthday.by_month <- function(ref, pos, cal_table, use_bizday = FALSE) { as.Date(dates, origin = as.Date("1970-01-01")) } -getnthday.by_year <- function(ref, pos, cal_table, use_bizday = FALSE) { +getnthday.by_year <- function(ref, pos, cal, use_bizday = FALSE) { ym_table <- unique(ref$ref_table) + cal_table <- cal$dates.table date_res <- lapply( seq_len(NROW(ym_table)), diff --git a/tests/testthat/test-getbizdays.R b/tests/testthat/test-getbizdays.R index bd18b3f..98b0bb0 100644 --- a/tests/testthat/test-getbizdays.R +++ b/tests/testthat/test-getbizdays.R @@ -18,13 +18,13 @@ test_that("getbizdays works with year-month", { }) test_that("getbizdays works with dates", { - dc <- getbizdays("2022-12-02", "actual") + dc <- getbizdays("2022-12", "actual") expect_equal(dc, 31) - dc <- getbizdays(as.Date("2022-12-02"), "actual") + dc <- getbizdays("2022-12", "actual") expect_equal(dc, 31) dts <- seq(as.Date("2022-01-01"), as.Date("2022-12-01"), by = "months") - dc <- getbizdays(dts, "actual") + dc <- getbizdays(format(dts, "%Y-%m"), "actual") expect_equal(dc, c(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)) }) \ No newline at end of file diff --git a/tests/testthat/test-getdate.R b/tests/testthat/test-getdate.R index 2bd6239..b9ad8f9 100644 --- a/tests/testthat/test-getdate.R +++ b/tests/testthat/test-getdate.R @@ -14,4 +14,15 @@ test_that("getdate", { "2018-11-01", "2018-12-03" )) expect_equal(dts_1, dts_2) +}) + +test_that("getdate by_day", { + x <- getdate("next day", Sys.Date(), "actual") + expect_equal(x, Sys.Date() + 1) + x <- getdate("last day", Sys.Date(), "actual") + expect_equal(x, Sys.Date() - 1) + x <- getdate("next bizday", "2022-06-18", "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-20")) + x <- getdate("last bizday", "2022-06-19", "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-17")) }) \ No newline at end of file diff --git a/tests/testthat/test-parsedate.R b/tests/testthat/test-parsedate.R index 95b8ccf..c0f0f6f 100644 --- a/tests/testthat/test-parsedate.R +++ b/tests/testthat/test-parsedate.R @@ -31,50 +31,46 @@ test_that("it should parse position token", { }) test_that("it should create a year-month reference", { - rrr <- ref(as.Date("2018-01-01"), "month") + rrr <- ref(as.Date("2018-01-01")) expect_is(rrr, "ref") - expect_true(rrr$by_month) - expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) - rrr <- ref(as.Date("2018-01-01"), "year") - expect_is(rrr, "ref") - expect_false(rrr$by_month) - expect_equal(rrr$ref_table, cbind(year = 2018)) - expect_error(ref(as.Date("2018-01-01"), "day")) - rrr <- ref(c(as.Date("2018-01-01"), as.Date("2018-02-01")), "month") + expect_is(rrr, "by_day") + expect_equal(rrr$dates, as.Date("2018-01-01")) + rrr <- ref(c(as.Date("2018-01-01"), as.Date("2018-02-01"))) expect_is(rrr, "ref") - expect_true(rrr$by_month) - expect_equal(rrr$ref_table, cbind(year = 2018, month = c(1, 2))) + expect_is(rrr, "by_day") + expect_equal(rrr$dates, c(as.Date("2018-01-01"), as.Date("2018-02-01"))) rrr <- ref("2018-01") expect_is(rrr, "ref") - expect_true(rrr$by_month) + expect_is(rrr, "by_month") expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) rrr <- ref("2018") expect_is(rrr, "ref") - expect_false(rrr$by_month) + expect_is(rrr, "by_year") expect_equal(rrr$ref_table, cbind(year = 2018)) rrr <- ref(2018) expect_is(rrr, "ref") - expect_false(rrr$by_month) + expect_is(rrr, "by_year") expect_equal(rrr$ref_table, cbind(year = 2018)) rrr <- ref(2010:2018) + expect_is(rrr, "by_year") expect_equal(rrr$ref_table, cbind(year = 2010:2018)) - rrr <- ref("2018-01-01", ym = "month") - expect_true(rrr$by_month) - expect_equal(rrr$ref_table, cbind(year = 2018, month = 1)) + rrr <- ref("2018-01-01") + expect_is(rrr, "by_day") + expect_equal(rrr$dates, as.Date("2018-01-01")) }) test_that("it should get the nth day by the reference", { - rrr <- ref(as.Date("2018-01-01"), "month") + rrr <- ref("2018-01") cal <- calendars()[["actual"]] - expect_equal(getnthday(rrr, 1, cal$dates.table), as.Date("2018-01-01")) - expect_equal(getnthday(rrr, -1, cal$dates.table), as.Date("2018-01-31")) + expect_equal(getnthday(rrr, 1, cal), as.Date("2018-01-01")) + expect_equal(getnthday(rrr, -1, cal), as.Date("2018-01-31")) cal <- calendars()[["Brazil/ANBIMA"]] expect_equal( - getnthday(rrr, 1, cal$dates.table, use_bizday = TRUE), + getnthday(rrr, 1, cal, use_bizday = TRUE), as.Date("2018-01-02") ) expect_equal( - getnthday(rrr, -1, cal$dates.table, use_bizday = TRUE), + getnthday(rrr, -1, cal, use_bizday = TRUE), as.Date("2018-01-31") ) }) \ No newline at end of file From 85ce6d2c07ff50b90061d014da6fc0639a893f3b Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Sun, 19 Jun 2022 22:51:30 -0300 Subject: [PATCH 4/8] Removed by_month ref attribute --- R/getbizdays.R | 22 ++++++++++++---------- R/getdate.R | 4 ---- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/R/getbizdays.R b/R/getbizdays.R index b06be32..8c9d430 100644 --- a/R/getbizdays.R +++ b/R/getbizdays.R @@ -22,9 +22,6 @@ #' # for months #' getbizdays("2022-12", "Brazil/ANBIMA") #' -#' # using dates as references for months -#' dts <- seq(as.Date("2022-01-01"), as.Date("2022-12-01"), by = "months") -#' getbizdays(dts, "Brazil/ANBIMA") #' @export getbizdays <- function(ref, cal = bizdays.options$get("default.calendar")) { cal <- check_calendar(cal) @@ -32,17 +29,22 @@ getbizdays <- function(ref, cal = bizdays.options$get("default.calendar")) { bizdays_ <- lapply( seq_len(NROW(ref$ref_table)), - function(x) count_bizdays_(ref, cal, x) + function(x) count_bizdays(ref, cal, x) ) unlist(bizdays_) } -count_bizdays_ <- function(ref, cal, ref_pos) { - ix <- if (ref$by_month) { - cal$dates.table[, "month"] == ref$ref_table[ref_pos, "month"] & - cal$dates.table[, "year"] == ref$ref_table[ref_pos, "year"] - } else { +count_bizdays <- function(x, ...) { + UseMethod("count_bizdays") +} + +count_bizdays.by_month <- function(ref, cal, ref_pos) { + ix <- cal$dates.table[, "month"] == ref$ref_table[ref_pos, "month"] & cal$dates.table[, "year"] == ref$ref_table[ref_pos, "year"] - } + sum(cal$dates.table[ix, "is_bizday"]) +} + +count_bizdays.by_year <- function(ref, cal, ref_pos) { + ix <- cal$dates.table[, "year"] == ref$ref_table[ref_pos, "year"] sum(cal$dates.table[ix, "is_bizday"]) } \ No newline at end of file diff --git a/R/getdate.R b/R/getdate.R index 5310fcc..6343ba0 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -111,7 +111,6 @@ ref.character <- function(x, ...) { ref.numeric <- function(x, ...) { that <- list( - by_month = FALSE, ref_table = cbind(year = x) ) structure(that, class = c("ref", "by_year")) @@ -119,7 +118,6 @@ ref.numeric <- function(x, ...) { ref_by_year <- function(year) { that <- list( - by_month = FALSE, ref_table = cbind(year = year) ) structure(that, class = c("ref", "by_year")) @@ -127,7 +125,6 @@ ref_by_year <- function(year) { ref_by_month <- function(year, month) { that <- list( - by_month = TRUE, ref_table = cbind( year = year, month = month @@ -138,7 +135,6 @@ ref_by_month <- function(year, month) { ref_by_day <- function(dates) { that <- list( - by_month = FALSE, dates = dates ) structure(that, class = c("ref", "by_day")) From 4c2145cd050e85dbcb8e78c4178a8ffe9a221c06 Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Sun, 19 Jun 2022 23:39:57 -0300 Subject: [PATCH 5/8] Updated docs --- R/getdate.R | 2 ++ man/getbizdays.Rd | 3 --- man/getdate.Rd | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/R/getdate.R b/R/getdate.R index 6343ba0..0063e04 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -45,6 +45,8 @@ #' getdate("last bizday", 2010:2018, "Brazil/ANBIMA") #' dts <- seq(as.Date("2018-01-01"), as.Date("2018-12-01"), "month") #' getdate("first bizday", format(dts, "%Y-%m"), "Brazil/ANBIMA") +#' getdate("last bizday", Sys.Date(), "Brazil/ANBIMA") +#' getdate("next bizday", Sys.Date(), "Brazil/ANBIMA") #' @export getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { cal <- check_calendar(cal) diff --git a/man/getbizdays.Rd b/man/getbizdays.Rd index 495e6ec..9166d52 100644 --- a/man/getbizdays.Rd +++ b/man/getbizdays.Rd @@ -31,7 +31,4 @@ getbizdays(2022:2024, "Brazil/ANBIMA") # for months getbizdays("2022-12", "Brazil/ANBIMA") -# using dates as references for months -dts <- seq(as.Date("2022-01-01"), as.Date("2022-12-01"), by = "months") -getbizdays(dts, "Brazil/ANBIMA") } diff --git a/man/getdate.Rd b/man/getdate.Rd index 7a47491..f34494a 100644 --- a/man/getdate.Rd +++ b/man/getdate.Rd @@ -55,4 +55,6 @@ getdate("10th wed", 2018, "Brazil/ANBIMA") getdate("last bizday", 2010:2018, "Brazil/ANBIMA") dts <- seq(as.Date("2018-01-01"), as.Date("2018-12-01"), "month") getdate("first bizday", format(dts, "\%Y-\%m"), "Brazil/ANBIMA") +getdate("last bizday", Sys.Date(), "Brazil/ANBIMA") +getdate("next bizday", Sys.Date(), "Brazil/ANBIMA") } From baf700c65aa60e74feb8a6b7280ebe109f6924bb Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Mon, 20 Jun 2022 07:33:05 -0300 Subject: [PATCH 6/8] Organized getnthweekday and getnthday arguments --- R/getdate.R | 18 ++++++++++-------- tests/testthat/test-parsedate.R | 8 ++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/R/getdate.R b/R/getdate.R index 0063e04..e80ea98 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -57,12 +57,12 @@ getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { } n <- getnth_(tok[1]) if (tok[2] == "day") { - getnthday(ref, n, cal, FALSE) + getnthday(ref, n, FALSE, cal) } else if (tok[2] == "bizday") { - getnthday(ref, n, cal, TRUE) + getnthday(ref, n, TRUE, cal) } else if (tok[2] %in% WEEKDAYS) { wday <- which(tok[2] == WEEKDAYS) - getnthweekday(ref, n, cal$dates.table, wday) + getnthweekday(ref, n, wday, cal) } else { stop("Invalid expr", expr) } @@ -173,7 +173,7 @@ getnthday <- function(ref, ...) { UseMethod("getnthday") } -getnthday.by_day <- function(ref, pos, cal, use_bizday = FALSE) { +getnthday.by_day <- function(ref, pos, use_bizday, cal) { if (use_bizday) { add.bizdays(ref$dates, pos, cal) } else { @@ -181,7 +181,7 @@ getnthday.by_day <- function(ref, pos, cal, use_bizday = FALSE) { } } -getnthday.by_month <- function(ref, pos, cal, use_bizday = FALSE) { +getnthday.by_month <- function(ref, pos, use_bizday, cal) { ym_table <- unique(ref$ref_table) cal_table <- cal$dates.table @@ -211,7 +211,7 @@ getnthday.by_month <- function(ref, pos, cal, use_bizday = FALSE) { as.Date(dates, origin = as.Date("1970-01-01")) } -getnthday.by_year <- function(ref, pos, cal, use_bizday = FALSE) { +getnthday.by_year <- function(ref, pos, use_bizday, cal) { ym_table <- unique(ref$ref_table) cal_table <- cal$dates.table @@ -244,8 +244,9 @@ getnthweekday <- function(ref, ...) { UseMethod("getnthweekday") } -getnthweekday.by_month <- function(ref, pos, cal_table, wday) { +getnthweekday.by_month <- function(ref, pos, wday, cal) { ym_table <- unique(ref$ref_table) + cal_table <- cal$dates.table date_res <- lapply( seq_len(NROW(ym_table)), @@ -273,8 +274,9 @@ getnthweekday.by_month <- function(ref, pos, cal_table, wday) { as.Date(dates, origin = as.Date("1970-01-01")) } -getnthweekday.by_year <- function(ref, pos, cal_table, wday) { +getnthweekday.by_year <- function(ref, pos, wday, cal) { ym_table <- unique(ref$ref_table) + cal_table <- cal$dates.table date_res <- lapply( seq_len(NROW(ym_table)), diff --git a/tests/testthat/test-parsedate.R b/tests/testthat/test-parsedate.R index c0f0f6f..7ae6800 100644 --- a/tests/testthat/test-parsedate.R +++ b/tests/testthat/test-parsedate.R @@ -62,15 +62,15 @@ test_that("it should create a year-month reference", { test_that("it should get the nth day by the reference", { rrr <- ref("2018-01") cal <- calendars()[["actual"]] - expect_equal(getnthday(rrr, 1, cal), as.Date("2018-01-01")) - expect_equal(getnthday(rrr, -1, cal), as.Date("2018-01-31")) + expect_equal(getnthday(rrr, 1, FALSE, cal), as.Date("2018-01-01")) + expect_equal(getnthday(rrr, -1, FALSE, cal), as.Date("2018-01-31")) cal <- calendars()[["Brazil/ANBIMA"]] expect_equal( - getnthday(rrr, 1, cal, use_bizday = TRUE), + getnthday(rrr, 1, TRUE, cal), as.Date("2018-01-02") ) expect_equal( - getnthday(rrr, -1, cal, use_bizday = TRUE), + getnthday(rrr, -1, TRUE, cal), as.Date("2018-01-31") ) }) \ No newline at end of file From 5923aabf2801b41a6ad642163fbb60a7dd380874 Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Mon, 20 Jun 2022 08:52:31 -0300 Subject: [PATCH 7/8] Implemented getnthweekday.by_day This allows calls like ``` r getdate("2nd wed", Sys.Date()) getdate("next wed", Sys.Date()) getdate("last wed", Sys.Date()) getdate("next mon", Sys.Date()) getdate("last mon", Sys.Date()) ``` --- R/getdate.R | 41 +++++++++++++++++++++++++++++++++++ man/getdate.Rd | 5 +++++ tests/testthat/test-getdate.R | 11 ++++++++++ 3 files changed, 57 insertions(+) diff --git a/R/getdate.R b/R/getdate.R index e80ea98..c503ed6 100644 --- a/R/getdate.R +++ b/R/getdate.R @@ -47,6 +47,11 @@ #' getdate("first bizday", format(dts, "%Y-%m"), "Brazil/ANBIMA") #' getdate("last bizday", Sys.Date(), "Brazil/ANBIMA") #' getdate("next bizday", Sys.Date(), "Brazil/ANBIMA") +#' getdate("2nd wed", Sys.Date()) +#' getdate("next wed", Sys.Date()) +#' getdate("last wed", Sys.Date()) +#' getdate("next mon", Sys.Date()) +#' getdate("last mon", Sys.Date()) #' @export getdate <- function(expr, ref, cal = bizdays.options$get("default.calendar")) { cal <- check_calendar(cal) @@ -244,6 +249,42 @@ getnthweekday <- function(ref, ...) { UseMethod("getnthweekday") } +getnthweekday.by_day <- function(ref, pos, wday, cal) { + ym_table <- unique(ref$dates) + cal_table <- cal$dates.table + + date_res <- lapply( + seq_along(ym_table), + function(x) { + n_date <- as.integer(ym_table[x]) + cur_wday <- (n_date %% 7) + 1 + ix_date <- which(cal_table[, "dates"] == n_date) + delta <- abs(cur_wday - wday) + + pos <- if (pos > 0) { + if (delta == 0 & pos == 1) { + ix_date + 7 + } else { + ix_date + (pos - 1) * 7 + delta + } + } else { + ix_date - (pos + 1) * 7 - (7 - delta) + } + date <- unname(cal_table[pos, "dates"]) + + idx <- ref$dates == ym_table[x] + list(date = date, index = idx) + } + ) + + dates <- integer(length(ref$dates)) + for (res in date_res) { + dates[res$index] <- res$date + } + + as.Date(dates, origin = as.Date("1970-01-01")) +} + getnthweekday.by_month <- function(ref, pos, wday, cal) { ym_table <- unique(ref$ref_table) cal_table <- cal$dates.table diff --git a/man/getdate.Rd b/man/getdate.Rd index f34494a..4fd94a9 100644 --- a/man/getdate.Rd +++ b/man/getdate.Rd @@ -57,4 +57,9 @@ dts <- seq(as.Date("2018-01-01"), as.Date("2018-12-01"), "month") getdate("first bizday", format(dts, "\%Y-\%m"), "Brazil/ANBIMA") getdate("last bizday", Sys.Date(), "Brazil/ANBIMA") getdate("next bizday", Sys.Date(), "Brazil/ANBIMA") +getdate("2nd wed", Sys.Date()) +getdate("next wed", Sys.Date()) +getdate("last wed", Sys.Date()) +getdate("next mon", Sys.Date()) +getdate("last mon", Sys.Date()) } diff --git a/tests/testthat/test-getdate.R b/tests/testthat/test-getdate.R index b9ad8f9..8ea77d7 100644 --- a/tests/testthat/test-getdate.R +++ b/tests/testthat/test-getdate.R @@ -25,4 +25,15 @@ test_that("getdate by_day", { expect_equal(x, as.Date("2022-06-20")) x <- getdate("last bizday", "2022-06-19", "Brazil/ANBIMA") expect_equal(x, as.Date("2022-06-17")) + + x <- getdate("2nd wed", as.Date("2022-06-20"), "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-29")) + x <- getdate("next wed", as.Date("2022-06-20"), "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-22")) + x <- getdate("last wed", as.Date("2022-06-20"), "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-15")) + x <- getdate("next mon", as.Date("2022-06-20"), "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-27")) + x <- getdate("last mon", as.Date("2022-06-20"), "Brazil/ANBIMA") + expect_equal(x, as.Date("2022-06-13")) }) \ No newline at end of file From e50d3fbf2f5075fec255608201cf00b2f5323aad Mon Sep 17 00:00:00 2001 From: wilsonfreitas Date: Mon, 20 Jun 2022 08:53:32 -0300 Subject: [PATCH 8/8] Version upgraded to 1.0.11 and NEWS updated --- DESCRIPTION | 2 +- NEWS.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 989542a..a417e80 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: bizdays Title: Business Days Calculations and Utilities Description: Business days calculations based on a list of holidays and nonworking weekdays. Quite useful for fixed income and derivatives pricing. -Version: 1.0.10 +Version: 1.0.11 Author: Wilson Freitas Maintainer: Wilson Freitas URL: https://github.com/wilsonfreitas/R-bizdays diff --git a/NEWS.md b/NEWS.md index 6259ab8..bf0874d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +# bizdays 1.0.11 + + * improved getdate to use a day as reference and allows expressions like: + `getdate("last bizday", Sys.Date(), "Brazil/ANBIMA")`, + `getdate("next wed", Sys.Date())`, ...(issue #28) + + * organized `ref` code to avoid duplicate code + # bizdays 1.0.10 * holidaysB3 data updated, the day 2020-07-09 has been removed, it's not a holiday.