Skip to content

Inconsistent between() behavior on dates due to NAbounds argument #7281

@grcatlin

Description

@grcatlin

I have noticed some inconsistent behavior using between(). Specifically, NAbounds = FALSE must be provided depending on the order of other filters.

Reprex

I have a dataset similar to the following. Basically some rows are "Active" and will have associated ranges of dates. I need to check if a row's date is in between the specified range for that row, which differs from row to row. However, if a row is not active, no corresponding ranges exist.

# verbose
options(datatable.verbose = TRUE)

# create data.table
x <- data.table::data.table(
    Date = seq(Sys.Date(), Sys.Date() + lubridate::years(30), by = "1 day")
)
x[, Active := sample(c(TRUE, FALSE), size = .N, replace = TRUE, prob = c(0.8, 0.2))]

# if active is TRUE, Date will either be inside or outside of generated ranges below
x[Active == TRUE, InRange := sample(c(TRUE, FALSE), size = .N, replace = TRUE)]
x[InRange == TRUE, c("RangeBegin", "RangeEnd") := list(Date - lubridate::days(20), Date + lubridate::days(20))]
x[InRange == FALSE, c("RangeBegin", "RangeEnd") := list(Date + lubridate::days(1), Date + lubridate::days(20))]

I would like to use between() to calculate the InRange column generated above. However, before doing that, even filtering the data is not consistent:

# succeeds
x[Active == TRUE][data.table::between(Date, RangeBegin, RangeEnd)]
Optimized subsetting with index 'Active'
forder.c received 1 rows and 1 columns
forderReuseSorting: opt=-1, took 0.000s
forder took 0.000 sec
x is already ordered by these columns, no need to call reorder
i.Active has same type (logical) as x.Active. No coercion needed.
on= matches existing index, using index
Starting bmerge ...
forderReuseSorting: using key: __Active
forderReuseSorting: opt=1, took 0.000s
bmerge: looping bmerge_r took 0.000s
bmerge: took 0.000s
bmerge done in 0.000s elapsed (0.000s cpu)
Constructing irows for '!byjoin || nqbyjoin' ... 0.000s elapsed (0.000s cpu) 
optimised between not available for this data type, fallback to slow R routine
# fails
x[Active == TRUE & data.table::between(Date, RangeBegin, RangeEnd)]
optimised between not available for this data type, fallback to slow R routine
Error in .checkTypos(e, names_x) : 
  Not yet implemented NAbounds=TRUE for this non-numeric and non-character type

However, by using NAbounds = FALSE it arrives at the same result.

# works again
x[Active == TRUE & data.table::between(Date, RangeBegin, RangeEnd, NAbounds = FALSE)]

I am trying to make this calculation in an fcase() operation in my actual data, though for this simple example it is more complex than necessary.

# toy calculation

# fails with same error
x[, InRangefcase := data.table::fcase(
    Active == FALSE, NA,
    Active == TRUE, data.table::between(Date, RangeBegin, RangeEnd)
)]

# succeeds
x[, InRangefcase := data.table::fcase(
    Active == FALSE, NA,
    Active == TRUE, data.table::between(Date, RangeBegin, RangeEnd, NAbounds = FALSE)
)]

# and is identical to the original column
all(x[, InRange] == x[, InRangefcase], na.rm = TRUE)

At any rate, I don't know if this behavior is intended but I found it pretty confusing in my actual data, made me think I had NA's in my RangeBegin and RangeEnd columns.

Thanks for the amazing package - I use it daily!

SessionInfo

R version 4.5.1 (2025-06-13)
Platform: aarch64-apple-darwin20
Running under: macOS Sequoia 15.6.1

Matrix products: default
BLAS:   /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils    
[5] datasets  methods   base     

other attached packages:
[1] fs_1.6.6

loaded via a namespace (and not attached):
[1] compiler_4.5.1    generics_0.1.4   
[3] cli_3.6.5         tools_4.5.1      
[5] lubridate_1.9.4   data.table_1.17.8
[7] jsonlite_2.0.0    timechange_0.3.0 
[9] rlang_1.1.6   

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions