Skip to content
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@

19. Ellipsis elements like `..1` are correctly excluded when searching for variables in "up-a-level" syntax inside `[`, [#5460](https://github.com/Rdatatable/data.table/issues/5460). Thanks @ggrothendieck for the report and @MichaelChirico for the fix.

20. BREAKING CHANGE: `week()` now calculates the week of the year sequentially (days 1-7 are week 1), fixing a bug where the first week could have 6 days. A one-time warning is now issued if this change affects the output for a given input, which can be disabled via `options(datatable.warn.week.change = FALSE)`. [#2611](https://github.com/Rdatatable/data.table/issues/2611). Thanks to @MichaelChirico for the report and @venom1204 for the fix.

### NOTES

1. The following in-progress deprecations have proceeded:
Expand Down
10 changes: 9 additions & 1 deletion inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -18384,7 +18384,7 @@ x = c("1111-11-11", "2019-01-01", "2019-02-28", "2019-03-01", "2019-12-31", "202
test(2236.1, yday(x), c(315L, 1L, 59L, 60L, 365L, 60L, 61L, 366L, 1L, 366L, 60L, NA))
test(2236.2, mday(x), c(11L, 1L, 28L, 1L, 31L, 29L, 1L, 31L, 1L, 31L, 1L, NA))
test(2236.3, wday(x), c(7L, 3L, 5L, 6L, 3L, 7L, 1L, 5L, 1L, 2L, 2L, NA))
test(2236.4, week(x), c(46L, 1L, 9L, 9L, 53L, 9L, 9L, 53L, 1L, 53L, 9L, NA))
test(2236.4, suppressWarnings(week(x)), c(45L, 1L, 9L, 9L, 53L, 9L, 9L, 53L, 1L, 53L, 9L, NA))
test(2236.5, month(x), c(11L, 1L, 2L, 3L, 12L, 2L, 3L, 12L, 1L, 12L, 3L, NA))
test(2236.6, quarter(x), c(4L, 1L, 1L, 1L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, NA))
test(2236.7, year(x), c(1111L, 2019L, 2019L, 2019L, 2019L, 2020L, 2020L, 2020L, 2040L, 2040L, 2100L, NA))
Expand Down Expand Up @@ -21815,3 +21815,11 @@ test(2341.24, fread('a
# leading cmnt
b
', comment.char = '#', strip.white = FALSE, sep = ","), data.table(a=c(" ", "b")))

# week() sequential numbering fix tests #2611
test(2342.1, week(as.IDate("1970-01-01") + 0:7), c(1L,1L,1L,1L,1L,1L,1L,2L)) # Jan 1–7 all week 1, Jan 8 week 2
test(2342.2, week(as.IDate(c("2012-02-28","2012-02-29","2012-03-01"))), c(9L,9L,9L)) # leap day stays in same week
test(2342.3, week(as.IDate(c("2019-12-31","2020-01-01"))), c(53L,1L)) # year boundary non-leap → reset to 1
test(2342.4, week(as.IDate(c("2020-12-31","2021-01-01"))), c(53L,1L)) # year boundary leap → reset to 1
test(2342.5, week(as.IDate("2021-01-06") + 0:6), c(1L,1L,2L,2L,2L,2L,2L))
test(2342.6, week(as.IDate(c("2016-02-27","2016-02-28","2016-02-29","2016-03-01","2016-03-02"))), c(9L,9L,9L,9L,9L))
27 changes: 26 additions & 1 deletion src/idatetime.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "data.table.h"

static int week_warning_issued = 0;

static const int YEARS400 = 146097;
static const int YEARS100 = 36524;
static const int YEARS4 = 1461;
Expand Down Expand Up @@ -64,7 +66,7 @@ void convertSingleDate(int x, datetype type, void *out)
yday -= YEARS1 + leap;
*(int *)out = ++yday;
if (type == WEEK)
*(int *)out = (*(int *)out / 7) + 1;
*(int *)out = ((*(int *)out - 1) / 7) + 1;
return;
}

Expand Down Expand Up @@ -143,6 +145,29 @@ SEXP convertDate(SEXP x, SEXP type)
else if (!strcmp(ctype_str, "yearqtr")) { ctype = YEARQTR; ansint = false; }
else internal_error(__func__, "invalid type, should have been caught before"); // # nocov

if (ctype == WEEK) {
if (!week_warning_issued) {
SEXP dt_week_warn_opt = GetOption(install("datatable.warn.week.change"), R_NilValue);
if (!isLogical(dt_week_warn_opt) || LOGICAL(dt_week_warn_opt)[0] != FALSE) {
for (int i = 0; i < n; i++) {
if (ix[i] == NA_INTEGER) continue;

int yday;
convertSingleDate(ix[i], YDAY, &yday);

int old_week = (yday / 7) + 1;
int new_week = ((yday - 1) / 7) + 1;

if (new_week != old_week) {
Rf_warning("data.table::week() behavior has changed and is now sequential (day 1-7 is week 1). The first week of the year may differ from previous versions. To suppress this warning, run: options(datatable.warn.week.change = FALSE)");
week_warning_issued = 1;
break;
}
}
}
}
}

if (ansint) {
SEXP ans = PROTECT(allocVector(INTSXP, n));
int *ansp = INTEGER(ans);
Expand Down
Loading