Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support iso-year-week-day in calendar_leap_year() #333

Merged
merged 3 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Depends:
Imports:
cli (>= 3.6.1),
rlang (>= 1.1.0),
tzdb (>= 0.3.0),
tzdb (>= 0.3.0.9000),
vctrs (>= 0.6.1)
Suggests:
covr,
Expand All @@ -35,7 +35,7 @@ Suggests:
withr
LinkingTo:
cpp11 (>= 0.4.3),
tzdb (>= 0.3.0)
tzdb (>= 0.3.0.9000)
VignetteBuilder:
knitr
Config/Needs/website:
Expand All @@ -46,3 +46,5 @@ Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Remotes:
r-lib/tzdb
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ S3method(calendar_is_valid_precision,clock_year_month_weekday)
S3method(calendar_is_valid_precision,clock_year_quarter_day)
S3method(calendar_is_valid_precision,clock_year_week_day)
S3method(calendar_leap_year,clock_calendar)
S3method(calendar_leap_year,clock_iso_year_week_day)
S3method(calendar_leap_year,clock_year_day)
S3method(calendar_leap_year,clock_year_month_day)
S3method(calendar_leap_year,clock_year_month_weekday)
Expand Down
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
the Epidemiological calendar used by the US CDC guidelines (similar to what
is supported by `lubridate::epiweek()` and `lubridate::epiyear()`) (#110).

* `calendar_leap_year()` now supports the year-quarter-day calendar (#332).
* `calendar_leap_year()` now supports the year-quarter-day and iso-year-week-day
calendars (#332, #333).

* Documented clock's current stance on leap seconds in the FAQ vignette (clock
ignores them like POSIXct) (#309).
Expand Down
8 changes: 6 additions & 2 deletions R/calendar.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,20 @@ cast_calendar_to_calendar <- function(x, to, ...) {
#'
#' - [year_month_weekday()]: February has a weekday that occurs 5 times.
#'
#' - [year_week_day()]: There are 53 weeks in the year.
#' - [year_week_day()]: There are 53 weeks in the year, resulting in 371
#' days in the year.
#'
#' - [year_day()]: There are 366 days in the year.
#' - [iso_year_week_day()]: There are 53 weeks in the year, resulting in 371
#' days in the year.
#'
#' - [year_quarter_day()]: One of the quarters has 1 more day than normal (the
#' quarter with an extra day depends on the `start` used, but will always be
#' the same for a particular `start`). This aligns with Gregorian leap years
#' for all `start`s except February, in which case the leap year is always 1
#' year after the Gregorian leap year.
#'
#' - [year_day()]: There are 366 days in the year.
#'
#' @param x `[calendar]`
#'
#' A calendar type to detect leap years in.
Expand Down
4 changes: 4 additions & 0 deletions R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,10 @@ iso_year_week_day_minus_iso_year_week_day_cpp <- function(x, y, precision_int) {
.Call(`_clock_iso_year_week_day_minus_iso_year_week_day_cpp`, x, y, precision_int)
}

iso_year_week_day_leap_year_cpp <- function(year) {
.Call(`_clock_iso_year_week_day_leap_year_cpp`, year)
}

clock_get_year_max <- function() {
.Call(`_clock_clock_get_year_max`)
}
Expand Down
8 changes: 8 additions & 0 deletions R/iso-year-week-day.R
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,14 @@ as.character.clock_iso_year_week_day <- function(x, ...) {

# ------------------------------------------------------------------------------

#' @export
calendar_leap_year.clock_iso_year_week_day <- function(x) {
year <- get_year(x)
iso_year_week_day_leap_year_cpp(year)
}

# ------------------------------------------------------------------------------

#' Grouping: iso-year-week-day
#'
#' @description
Expand Down
7 changes: 5 additions & 2 deletions man/calendar_leap_year.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,13 @@ extern "C" SEXP _clock_iso_year_week_day_minus_iso_year_week_day_cpp(SEXP x, SEX
return cpp11::as_sexp(iso_year_week_day_minus_iso_year_week_day_cpp(cpp11::as_cpp<cpp11::decay_t<cpp11::list_of<cpp11::integers>>>(x), cpp11::as_cpp<cpp11::decay_t<cpp11::list_of<cpp11::integers>>>(y), cpp11::as_cpp<cpp11::decay_t<const cpp11::integers&>>(precision_int)));
END_CPP11
}
// iso-year-week-day.cpp
cpp11::writable::logicals iso_year_week_day_leap_year_cpp(const cpp11::integers& year);
extern "C" SEXP _clock_iso_year_week_day_leap_year_cpp(SEXP year) {
BEGIN_CPP11
return cpp11::as_sexp(iso_year_week_day_leap_year_cpp(cpp11::as_cpp<cpp11::decay_t<const cpp11::integers&>>(year)));
END_CPP11
}
// limits.cpp
int clock_get_year_max();
extern "C" SEXP _clock_clock_get_year_max() {
Expand Down Expand Up @@ -1018,6 +1025,7 @@ static const R_CallMethodDef CallEntries[] = {
{"_clock_invalid_resolve_year_month_weekday_cpp", (DL_FUNC) &_clock_invalid_resolve_year_month_weekday_cpp, 3},
{"_clock_invalid_resolve_year_quarter_day_cpp", (DL_FUNC) &_clock_invalid_resolve_year_quarter_day_cpp, 4},
{"_clock_invalid_resolve_year_week_day_cpp", (DL_FUNC) &_clock_invalid_resolve_year_week_day_cpp, 4},
{"_clock_iso_year_week_day_leap_year_cpp", (DL_FUNC) &_clock_iso_year_week_day_leap_year_cpp, 1},
{"_clock_iso_year_week_day_minus_iso_year_week_day_cpp", (DL_FUNC) &_clock_iso_year_week_day_minus_iso_year_week_day_cpp, 3},
{"_clock_iso_year_week_day_plus_duration_cpp", (DL_FUNC) &_clock_iso_year_week_day_plus_duration_cpp, 4},
{"_clock_iso_year_week_day_restore", (DL_FUNC) &_clock_iso_year_week_day_restore, 2},
Expand Down
21 changes: 21 additions & 0 deletions src/iso-year-week-day.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,24 @@ iso_year_week_day_minus_iso_year_week_day_cpp(cpp11::list_of<cpp11::integers> x,

never_reached("iso_year_week_day_minus_iso_year_week_day_cpp");
}

// -----------------------------------------------------------------------------

[[cpp11::register]]
cpp11::writable::logicals
iso_year_week_day_leap_year_cpp(const cpp11::integers& year) {
const r_ssize size = year.size();
cpp11::writable::logicals out(size);

for (r_ssize i = 0; i < size; ++i) {
const int elt = year[i];

if (elt == r_int_na) {
out[i] = r_lgl_na;
} else {
out[i] = iso_week::year{elt}.is_leap();
}
}

return out;
}
21 changes: 21 additions & 0 deletions tests/testthat/test-iso-year-week-day.R
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,27 @@ test_that("can compute week end", {
expect_identical(calendar_end(x, "week"), expect)
})

# ------------------------------------------------------------------------------
# calendar_leap_year()

test_that("can detect leap years", {
# Exactly 71 leap weeks for any 400 year cycle
start <- 1900L

while (start < 2000L) {
# `- 1L` to have exactly 400 years considered in the range since both
# `start` and `end` are included by `seq()`
end <- start + 400L - 1L
x <- iso_year_week_day(seq(start, end))
expect_identical(sum(calendar_leap_year(x)), 71L)
start <- start + 1L
}
})

test_that("`NA` propagates", {
expect_identical(calendar_leap_year(iso_year_week_day(NA)), NA)
})

# ------------------------------------------------------------------------------
# calendar_count_between()

Expand Down