Skip to content
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
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@

39. `shift(x, 0:1, type='lead', give.names=TRUE)` uses `lead` in all returned column names, [#3832](https://github.com/Rdatatable/data.table/issues/3832). Thanks @daynefiler for the report.

39. Subtracting two `POSIXt` objects by group could lead to incorrect results because the `base` method internally calls `difftime` with `units='auto'`; `data.table` does not notice if the chosen units differ by group and only the last group's `units` attribute was retained, [#3694](https://github.com/Rdatatable/data.table/issues/3694) and [#761](https://github.com/Rdatatable/data.table/issues/761). To surmount this, we now internally force `units='secs'` on all `POSIXt-POSIXt` calls (reported when `verbose=TRUE`); generally we recommend calling `difftime` directly instead. Thanks @oliver-oliver and @boethian for the reports.

#### NOTES

1. `rbindlist`'s `use.names="check"` now emits its message for automatic column names (`"V[0-9]+"`) too, [#3484](https://github.com/Rdatatable/data.table/pull/3484). See news item 5 of v1.12.2 below.
Expand Down
13 changes: 13 additions & 0 deletions R/data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -1327,6 +1327,19 @@ replace_dot_alias = function(e) {
SDenv$.N = vector("integer", 1L) # explicit new vector (not 0L or as.integer() which might return R's internal small-integer global)
SDenv$.GRP = vector("integer", 1L) # because written to by reference at C level (one write per group). TODO: move this alloc to C level

# #3694/#761 common gotcha -- doing t1-t0 by group, but -.POSIXt uses units='auto'
# independently by group & attr mismatch among groups is ignored. The latter
# is a more general issue but the former can be fixed by forcing units='secs'
SDenv$`-.POSIXt` = function(e1, e2) {
if (inherits(e2, 'POSIXt')) {
if (verbose && !exists('done_units_report', parent.frame())) {
cat('\nNote: forcing units="secs" on implicit difftime by group; call difftime explicitly to choose custom units')
assign('done_units_report', TRUE, parent.frame())
}
return(difftime(e1, e2, units='secs'))
} else return(base::`-.POSIXt`(e1, e2))
}

if (byjoin) {
# The groupings come instead from each row of the i data.table.
# Much faster for a few known groups vs a 'by' for all followed by a subset
Expand Down
7 changes: 7 additions & 0 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -15991,6 +15991,13 @@ test(2102.3, cut(ID, breaks = '6 months'), as.IDate(cut(D, breaks = '6 months'))
# DT[ , !rep(FALSE, ncol(DT)), with=FALSE] would exit before doing !, #3013
test(2103, DT[ , !rep(FALSE, 2L), with=FALSE], DT)

# implicit difftime by group can choose different units but are later ignored, #3694 & #761 (among others)
del = c(0, 60, 3600, 86400)
DT = data.table(ID=1:4, t0=.POSIXct(0), t1=.POSIXct(del))
test(2104.1, DT[ , t1-t0, by=ID], data.table(ID=1:4, V1=as.difftime(del, units='secs')))
test(2104.2, DT[ , t1-t0, by=ID, verbose=TRUE], output='Note: forcing units="secs"')
test(2104.3, DT[ , t1-5, by=ID], data.table(ID=1:4, V1=.POSIXct(del-5)))


###################################
# Add new tests above this line #
Expand Down