Skip to content

Commit 6477201

Browse files
committed
updated logic
1 parent 63355f3 commit 6477201

File tree

3 files changed

+43
-18
lines changed

3 files changed

+43
-18
lines changed

NEWS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
3939
1. `data.table(x=1, <expr>)`, where `<expr>` is an expression resulting in a 1-column matrix without column names, will eventually have names `x` and `V2`, not `x` and `V1`, consistent with `data.table(x=1, <expr>)` where `<expr>` results in an atomic vector, for example `data.table(x=1, cbind(1))` and `data.table(x=1, 1)` will both have columns named `x` and `V2`. In this release, the matrix case continues to be named `V1`, but the new behavior can be activated by setting `options(datatable.old.matrix.autoname)` to `FALSE`. See point 5 under Bug Fixes for more context; this change will provide more internal consistency as well as more consistency with `data.frame()`.
4040
41+
2. The `week()` function will be fixed in a future release to correctly calculate weeks sequentially (days 1-7 as week 1), which is a potential breaking change. For now, the current (buggy) behavior remains the default. A one-time deprecation warning will be issued when the old and new behaviors differ; this can be suppressed with `options(datatable.warn.week.deprecation = FALSE)`. Users can opt-in to the correct behavior now with the temporary option `options(datatable.week.new = TRUE)`. See [#2611](https://github.com/Rdatatable/data.table/issues/2611) for details. Thanks @MichaelChirico for the report.
42+
4143
### NEW FEATURES
4244
4345
1. New `sort_by()` method for data.tables, [#6662](https://github.com/Rdatatable/data.table/issues/6662). It uses `forder()` to improve upon the data.frame method and also matches `DT[order(...)]` behavior with respect to locale. Thanks @rikivillalba for the suggestion and PR.
@@ -333,8 +335,6 @@
333335
334336
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.
335337
336-
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.
337-
338338
### NOTES
339339
340340
1. The following in-progress deprecations have proceeded:

inst/tests/tests.Rraw

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18384,7 +18384,7 @@ x = c("1111-11-11", "2019-01-01", "2019-02-28", "2019-03-01", "2019-12-31", "202
1838418384
test(2236.1, yday(x), c(315L, 1L, 59L, 60L, 365L, 60L, 61L, 366L, 1L, 366L, 60L, NA))
1838518385
test(2236.2, mday(x), c(11L, 1L, 28L, 1L, 31L, 29L, 1L, 31L, 1L, 31L, 1L, NA))
1838618386
test(2236.3, wday(x), c(7L, 3L, 5L, 6L, 3L, 7L, 1L, 5L, 1L, 2L, 2L, NA))
18387-
test(2236.4, suppressWarnings(week(x)), c(45L, 1L, 9L, 9L, 53L, 9L, 9L, 53L, 1L, 53L, 9L, NA))
18387+
test(2236.4, week(x), c(46L, 1L, 9L, 9L, 53L, 9L, 9L, 53L, 1L, 53L, 9L, NA), warning="The current behavior of data.table::week() is deprecated")
1838818388
test(2236.5, month(x), c(11L, 1L, 2L, 3L, 12L, 2L, 3L, 12L, 1L, 12L, 3L, NA))
1838918389
test(2236.6, quarter(x), c(4L, 1L, 1L, 1L, 4L, 1L, 1L, 4L, 1L, 4L, 1L, NA))
1839018390
test(2236.7, year(x), c(1111L, 2019L, 2019L, 2019L, 2019L, 2020L, 2020L, 2020L, 2040L, 2040L, 2100L, NA))
@@ -21817,6 +21817,7 @@ b
2181721817
', comment.char = '#', strip.white = FALSE, sep = ","), data.table(a=c(" ", "b")))
2181821818

2181921819
# week() sequential numbering fix tests #2611
21820+
options(datatable.week.new = TRUE)
2182021821
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
2182121822
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
2182221823
test(2342.3, week(as.IDate(c("2019-12-31","2020-01-01"))), c(53L,1L)) # year boundary non-leap → reset to 1

src/idatetime.c

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "data.table.h"
22

3-
static int week_warning_issued = 0;
3+
static int week_deprecation_warning_issued = 0;
44

55
static const int YEARS400 = 146097;
66
static const int YEARS100 = 36524;
@@ -65,8 +65,15 @@ void convertSingleDate(int x, datetype type, void *out)
6565
if (yday >= YEARS1 + leap)
6666
yday -= YEARS1 + leap;
6767
*(int *)out = ++yday;
68-
if (type == WEEK)
69-
*(int *)out = ((*(int *)out - 1) / 7) + 1;
68+
if (type == WEEK) {
69+
SEXP opt_new = GetOption(install("datatable.week.new"), R_NilValue);
70+
bool use_new_behavior = isLogical(opt_new) && LOGICAL(opt_new)[0] == TRUE;
71+
if (use_new_behavior) {
72+
*(int *)out = ((*(int *)out - 1) / 7) + 1;
73+
} else {
74+
*(int *)out = (*(int *)out / 7) + 1;
75+
}
76+
}
7077
return;
7178
}
7279

@@ -146,26 +153,43 @@ SEXP convertDate(SEXP x, SEXP type)
146153
else internal_error(__func__, "invalid type, should have been caught before"); // # nocov
147154

148155
if (ctype == WEEK) {
149-
if (!week_warning_issued) {
150-
SEXP dt_week_warn_opt = GetOption(install("datatable.warn.week.change"), R_NilValue);
151-
if (!isLogical(dt_week_warn_opt) || LOGICAL(dt_week_warn_opt)[0] != FALSE) {
152-
for (int i = 0; i < n; i++) {
153-
if (ix[i] == NA_INTEGER) continue;
156+
SEXP ans = PROTECT(allocVector(INTSXP, n));
157+
int *ansp = INTEGER(ans);
154158

155-
int yday;
156-
convertSingleDate(ix[i], YDAY, &yday);
159+
SEXP opt_new = GetOption(install("datatable.week.new"), R_NilValue);
160+
bool use_new_behavior = isLogical(opt_new) && LOGICAL(opt_new)[0] == TRUE;
157161

158-
int old_week = (yday / 7) + 1;
159-
int new_week = ((yday - 1) / 7) + 1;
162+
bool can_warn = false;
163+
if (!use_new_behavior && !week_deprecation_warning_issued) {
164+
SEXP opt_warn_depr = GetOption(install("datatable.warn.week.deprecation"), R_NilValue);
165+
can_warn = !isLogical(opt_warn_depr) || LOGICAL(opt_warn_depr)[0] != FALSE;
166+
}
160167

168+
for (int i = 0; i < n; i++) {
169+
if (ix[i] == NA_INTEGER) {
170+
ansp[i] = NA_INTEGER;
171+
continue;
172+
}
173+
int yday;
174+
convertSingleDate(ix[i], YDAY, &yday);
175+
176+
if (use_new_behavior) {
177+
ansp[i] = ((yday - 1) / 7) + 1;
178+
} else {
179+
int old_week = (yday / 7) + 1;
180+
ansp[i] = old_week;
181+
if (can_warn) {
182+
int new_week = ((yday - 1) / 7) + 1;
161183
if (new_week != old_week) {
162-
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)");
163-
week_warning_issued = 1;
164-
break;
184+
Rf_warning("The current behavior of data.table::week() is deprecated and will be fixed in a future version to be sequential (day 1-7 is week 1). To opt-in to the new behavior now, run: options(datatable.week.new = TRUE). To suppress this warning, run: options(datatable.warn.week.deprecation = FALSE)");
185+
week_deprecation_warning_issued = 1;
186+
can_warn = false;
165187
}
166188
}
167189
}
168190
}
191+
UNPROTECT(1);
192+
return ans;
169193
}
170194

171195
if (ansint) {

0 commit comments

Comments
 (0)