From 41624b160a0d1be8ffc837b23818a58e050d152b Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Fri, 9 Jan 2026 17:27:22 -0800 Subject: [PATCH 1/3] New tests confirming support for Date, POSIXct --- NEWS.md | 2 +- inst/tests/nafill.Rraw | 64 +++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index e10b9348f..5c96c24c6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -14,7 +14,7 @@ ### NEW FEATURES -1. `nafill()`, `setnafill()` extended to work on logical and factor vectors (part of [#3992](https://github.com/Rdatatable/data.table/issues/3992)). `nafill()` works for character vectors, but not yet `setnafill()`. Thanks @jangorecki for the request and @jangorecki and @MichaelChirico for the PRs. +1. `nafill()`, `setnafill()` extended to work on logical and factor vectors (part of [#3992](https://github.com/Rdatatable/data.table/issues/3992)). Includes support for `Date`, `IDate`, `POSIXct`, etc. `nafill()` works for character vectors, but not yet `setnafill()`. Thanks @jangorecki for the request and @jangorecki and @MichaelChirico for the PRs. 2. `[,showProgress=]` and `options(datatable.showProgress)` now accept an integer to control the progress bar update interval in seconds, allowing finer control over progress reporting frequency; `TRUE` uses the default 3-second interval, [#6514](https://github.com/Rdatatable/data.table/issues/6514). Thanks @ethanbsmith for the report and @ben-schwen for the PR. diff --git a/inst/tests/nafill.Rraw b/inst/tests/nafill.Rraw index 9167c68cd..3b0e91031 100644 --- a/inst/tests/nafill.Rraw +++ b/inst/tests/nafill.Rraw @@ -380,6 +380,44 @@ test(14.13, options=c(datatable.verbose=TRUE), nafill(x, fill="z"), c("z", "z", "a", "b", "z", "z", "c", "d", "z", "z"), output="nafillString: took") +## other common classed vector objects: Date, IDate, POSIXct +x = as.IDate(c(NA, "2025-01-01", NA, "2025-06-01", NA)) +y26 = as.IDate("2026-01-01") +test(15.01, nafill(x, fill=y26), replace(x, c(1L, 3L, 5L), y26)) +test(15.02, nafill(x, fill=NA), x) +test(15.03, nafill(x, "locf"), replace(x, c(3L, 5L), x[c(2L, 4L)])) +test(15.04, nafill(x, "nocb"), replace(x, c(1L, 3L), x[c(2L, 4L)])) +test(15.05, nafill(x, "locf", fill=y26), replace(x, c(1L, 3L, 5L), c(y26, x[c(2L, 4L)]))) +test(15.06, nafill(x, "nocb", fill=y26), replace(x, c(1L, 3L, 5L), c(x[c(2L, 4L)], y26))) +test(15.07, nafill(x, fill=as.numeric(y26)), replace(x, c(1L, 3L, 5L), y26)) + +x = as.Date(x) +y26 = as.Date(y26) +test(15.08, nafill(x, fill=y26), replace(x, c(1L, 3L, 5L), y26)) +test(15.09, nafill(x, fill=NA), x) +test(15.10, nafill(x, "locf"), replace(x, c(3L, 5L), x[c(2L, 4L)])) +test(15.11, nafill(x, "nocb"), replace(x, c(1L, 3L), x[c(2L, 4L)])) +test(15.12, nafill(x, "locf", fill=y26), replace(x, c(1L, 3L, 5L), c(y26, x[c(2L, 4L)]))) +test(15.13, nafill(x, "nocb", fill=y26), replace(x, c(1L, 3L, 5L), c(x[c(2L, 4L)], y26))) +test(15.14, nafill(x, fill=as.numeric(y26)), replace(x, c(1L, 3L, 5L), y26)) + +x = as.POSIXct(x) +y26 = as.POSIXct(y26) +test(15.15, nafill(x, fill=y26), replace(x, c(1L, 3L, 5L), y26)) +test(15.16, nafill(x, fill=NA), x) +test(15.17, nafill(x, "locf"), replace(x, c(3L, 5L), x[c(2L, 4L)])) +test(15.18, nafill(x, "nocb"), replace(x, c(1L, 3L), x[c(2L, 4L)])) +test(15.19, nafill(x, "locf", fill=y26), replace(x, c(1L, 3L, 5L), c(y26, x[c(2L, 4L)]))) +test(15.20, nafill(x, "nocb", fill=y26), replace(x, c(1L, 3L, 5L), c(x[c(2L, 4L)], y26))) +test(15.21, nafill(x, fill=as.numeric(y26)), replace(x, c(1L, 3L, 5L), y26)) + +attr(x, "tzone") = "Asia/Singapore" +test(15.22, nafill(x, fill=y26), replace(x, c(1L, 3L, 5L), y26)) + +test(15.23, nafill(as.Date(NA), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) +test(15.24, nafill(as.Date(NA_integer_), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) +test(15.25, nafill(as.IDate(NA), fill=as.Date("2025-01-01")), as.IDate("2025-01-01")) + ## setnafill DT = data.table(l1=c(NA, NA, TRUE, TRUE, NA, NA, FALSE, FALSE, NA, NA), l2=c(NA, NA, FALSE, FALSE, NA, NA, TRUE, TRUE, NA, NA), @@ -391,39 +429,39 @@ DT = data.table(l1=c(NA, NA, TRUE, TRUE, NA, NA, FALSE, FALSE, NA, NA), f2=as.factor(c(NA, NA, "c", "b", NA, NA, "b", "a", NA, NA)), c1=c(NA, NA, "a", "b", NA, NA, "c", "d", NA, NA), c2=c(NA, NA, "d", "c", NA, NA, "b", "a", NA, NA)) -test(15.01, setnafill(copy(DT), fill=TRUE, cols='l1')$l1, +test(16.01, setnafill(copy(DT), fill=TRUE, cols='l1')$l1, c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE)) -test(15.02, setnafill(copy(DT), fill=TRUE, cols=c('l1', 'l2'))[, .(l1, l2)], +test(16.02, setnafill(copy(DT), fill=TRUE, cols=c('l1', 'l2'))[, .(l1, l2)], data.table(l1=c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE), l2=c(TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE))) -test(15.03, setnafill(copy(DT), fill=9L, cols='i1')$i1, +test(16.03, setnafill(copy(DT), fill=9L, cols='i1')$i1, c(9L, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L)) -test(15.04, setnafill(copy(DT), fill=9L, cols=c('i1', 'i2'))[, .(i1, i2)], +test(16.04, setnafill(copy(DT), fill=9L, cols=c('i1', 'i2'))[, .(i1, i2)], data.table(i1=c(9L, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L), i2=c(9L, 9L, 3:2, 9L, 9L, 1:0, 9L, 9L))) -test(15.05, setnafill(copy(DT), fill=9.0, cols='d1')$d1, +test(16.05, setnafill(copy(DT), fill=9.0, cols='d1')$d1, c(9.0, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L)) -test(15.06, setnafill(copy(DT), fill=9.0, cols=c('d1', 'd2'))[, .(d1, d2)], +test(16.06, setnafill(copy(DT), fill=9.0, cols=c('d1', 'd2'))[, .(d1, d2)], data.table(d1=c(9.0, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L), d2=c(9.0, 9L, 3:2, 9L, 9L, 1:0, 9L, 9L))) -test(15.07, setnafill(copy(DT), fill="a", cols='f1')$f1, +test(16.07, setnafill(copy(DT), fill="a", cols='f1')$f1, as.factor(c("a", "a", "a", "b", "a", "a", "b", "c", "a", "a"))) -test(15.08, setnafill(copy(DT), fill="a", cols=c('f1', 'f2'))[, .(f1, f2)], +test(16.08, setnafill(copy(DT), fill="a", cols=c('f1', 'f2'))[, .(f1, f2)], data.table(f1=as.factor(c("a", "a", "a", "b", "a", "a", "b", "c", "a", "a")), f2=as.factor(c("a", "a", "c", "b", "a", "a", "b", "a", "a", "a")))) -test(15.09, setnafill(DT, fill="z", cols='c1'), error="not yet supported") -# test(15.10, setnafill(copy(DT), fill="z", cols=c('c1', 'c2'))[, .(c1, c2)], +test(16.09, setnafill(DT, fill="z", cols='c1'), error="not yet supported") +# test(16.10, setnafill(copy(DT), fill="z", cols=c('c1', 'c2'))[, .(c1, c2)], # data.table(c1=c("z", "z", "a", "b", "z", "z", "c", "d", "z", "z"), # c2=c("z", "z", "d", "c", "z", "z", "b", "a", "z", "z"))) -test(15.11, setnafill(copy(DT), fill=list(TRUE, 9L, 9.0, "a"), cols=c("l1", "i1", "d1", "f1"))[, .(l1, i1, d1, f1)], +test(16.11, setnafill(copy(DT), fill=list(TRUE, 9L, 9.0, "a"), cols=c("l1", "i1", "d1", "f1"))[, .(l1, i1, d1, f1)], data.table(l1=c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE), i1=c(9L, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L), d1=c(9.0, 9L, 0L, 1L, 9L, 9L, 2:3, 9L, 9L), f1=as.factor(c("a", "a", "a", "b", "a", "a", "b", "c", "a", "a")))) -test(15.12, setnafill(DT, cols=c("l1", "c1")), error="not yet supported") +test(16.12, setnafill(DT, cols=c("l1", "c1")), error="not yet supported") DT = data.table(l=c(NA, FALSE), i=c(NA, 0L)) setnafill(DT, fill=list(TRUE, 1L)) -test(15.13, DT, data.table(l=c(TRUE, FALSE), i=1:0)) +test(16.13, DT, data.table(l=c(TRUE, FALSE), i=1:0)) ## Date ## POSIXct From f0d0a78604293a072469a46188897c99d394e478 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sat, 10 Jan 2026 16:08:59 -0800 Subject: [PATCH 2/3] use SEXP for char_v type --- src/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.h b/src/types.h index 44dfc75ac..d0358f4b2 100644 --- a/src/types.h +++ b/src/types.h @@ -10,7 +10,7 @@ typedef struct ans_t { int32_t *int_v; // used in nafill double *dbl_v; // used in froll, nafill int64_t *int64_v; // used in nafill - void *char_v; // ineligible for filling in parallel! + SEXP char_v; // ineligible for filling in parallel! uint8_t status; // 0:ok, 1:message, 2:warning, 3:error; unix return signal: {0,1,2}=0, {3}=1 char message[4][ANS_MSG_SIZE]; // STDOUT: output, STDERR: message, warning, error // implicit n_message limit discussed here: https://github.com/Rdatatable/data.table/issues/3423#issuecomment-487722586 From 7f64a787ac0b24d8cc0e851fc602272a6de386ca Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sat, 10 Jan 2026 16:11:38 -0800 Subject: [PATCH 3/3] more tests (attr, setnafill) --- inst/tests/nafill.Rraw | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/inst/tests/nafill.Rraw b/inst/tests/nafill.Rraw index 3b0e91031..6428be9af 100644 --- a/inst/tests/nafill.Rraw +++ b/inst/tests/nafill.Rraw @@ -413,10 +413,11 @@ test(15.21, nafill(x, fill=as.numeric(y26)), replace(x, c(1L, 3L, 5L), y26)) attr(x, "tzone") = "Asia/Singapore" test(15.22, nafill(x, fill=y26), replace(x, c(1L, 3L, 5L), y26)) +test(15.23, nafill(x, fill=as.POSIXct(y26, tz='Asia/Singapore')), replace(x, c(1L, 3L, 5L), y26)) -test(15.23, nafill(as.Date(NA), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) -test(15.24, nafill(as.Date(NA_integer_), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) -test(15.25, nafill(as.IDate(NA), fill=as.Date("2025-01-01")), as.IDate("2025-01-01")) +test(15.24, nafill(as.Date(NA), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) +test(15.25, nafill(as.Date(NA_integer_), fill=as.IDate("2025-01-01")), as.Date("2025-01-01")) +test(15.26, nafill(as.IDate(NA), fill=as.Date("2025-01-01")), as.IDate("2025-01-01")) ## setnafill DT = data.table(l1=c(NA, NA, TRUE, TRUE, NA, NA, FALSE, FALSE, NA, NA), @@ -428,7 +429,9 @@ DT = data.table(l1=c(NA, NA, TRUE, TRUE, NA, NA, FALSE, FALSE, NA, NA), f1=as.factor(c(NA, NA, "a", "b", NA, NA, "b", "c", NA, NA)), f2=as.factor(c(NA, NA, "c", "b", NA, NA, "b", "a", NA, NA)), c1=c(NA, NA, "a", "b", NA, NA, "c", "d", NA, NA), - c2=c(NA, NA, "d", "c", NA, NA, "b", "a", NA, NA)) + c2=c(NA, NA, "d", "c", NA, NA, "b", "a", NA, NA), + t1=as.POSIXct(c(NA, NA, "2025-01-01", "2025-01-02", NA, NA, "2025-06-01", "2025-06-02", NA, NA)), + t2=as.POSIXct(c(NA, NA, "2026-01-01", "2026-01-02", NA, NA, "2026-06-01", "2026-06-02", NA, NA))) test(16.01, setnafill(copy(DT), fill=TRUE, cols='l1')$l1, c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE)) test(16.02, setnafill(copy(DT), fill=TRUE, cols=c('l1', 'l2'))[, .(l1, l2)], @@ -453,20 +456,21 @@ test(16.09, setnafill(DT, fill="z", cols='c1'), error="not yet supported") # test(16.10, setnafill(copy(DT), fill="z", cols=c('c1', 'c2'))[, .(c1, c2)], # data.table(c1=c("z", "z", "a", "b", "z", "z", "c", "d", "z", "z"), # c2=c("z", "z", "d", "c", "z", "z", "b", "a", "z", "z"))) -test(16.11, setnafill(copy(DT), fill=list(TRUE, 9L, 9.0, "a"), cols=c("l1", "i1", "d1", "f1"))[, .(l1, i1, d1, f1)], +test(16.11, setnafill(copy(DT), fill=as.POSIXct("2027-01-01"), cols='t1')$t1, + replace(DT$t1, c(1:2, 5:6, 9:10), as.POSIXct("2027-01-01"))) +test(16.12, setnafill(copy(DT), fill=as.POSIXct("2027-01-01"), cols=c('t1', 't2'))[, .(t1, t2)], + data.table(t1=replace(DT$t1, c(1:2, 5:6, 9:10), as.POSIXct("2027-01-01")), + t2=replace(DT$t2, c(1:2, 5:6, 9:10), as.POSIXct("2027-01-01")))) +test(16.13, setnafill(copy(DT), fill=list(TRUE, 9L, 9.0, "a", as.POSIXct("2027-01-01")), cols=c("l1", "i1", "d1", "f1", "t1"))[, .(l1, i1, d1, f1, t1)], data.table(l1=c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE), i1=c(9L, 9L, 0:1, 9L, 9L, 2:3, 9L, 9L), d1=c(9.0, 9L, 0L, 1L, 9L, 9L, 2:3, 9L, 9L), - f1=as.factor(c("a", "a", "a", "b", "a", "a", "b", "c", "a", "a")))) -test(16.12, setnafill(DT, cols=c("l1", "c1")), error="not yet supported") + f1=as.factor(c("a", "a", "a", "b", "a", "a", "b", "c", "a", "a")), + t1=replace(DT$t1, c(1:2, 5:6, 9:10), as.POSIXct("2027-01-01")))) +test(16.14, setnafill(DT, cols=c("l1", "c1")), error="not yet supported") DT = data.table(l=c(NA, FALSE), i=c(NA, 0L)) setnafill(DT, fill=list(TRUE, 1L)) -test(16.13, DT, data.table(l=c(TRUE, FALSE), i=1:0)) - -## Date -## POSIXct -## IDate -## ITime +test(16.15, DT, data.table(l=c(TRUE, FALSE), i=1:0)) # related to !is.integer(verbose) test(99.1, data.table(a=1,b=2)[1,1, verbose=1], error="verbose must be logical or integer")