diff --git a/NEWS.md b/NEWS.md index 3c60946abd..e72ea27667 100644 --- a/NEWS.md +++ b/NEWS.md @@ -251,6 +251,8 @@ 36. `DT[id==1, DT2[.SD, on="id"]]` (i.e. joining from `.SD` in `j`) could incorrectly fail in some cases due to `.SD` being locked, [#1926](https://github.com/Rdatatable/data.table/issues/1926). Thanks @franknarf1 for the report and for diligently tracking use cases for almost 3 years! +37. `as.IDate.POSIXct` returned `NA` for UTC times before Dec 1901 and after Jan 2038, [#3780](https://github.com/Rdatatable/data.table/issues/3780). Thanks @gschett for the report. + #### 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. diff --git a/R/IDateTime.R b/R/IDateTime.R index 8e03631066..c0e31bc248 100644 --- a/R/IDateTime.R +++ b/R/IDateTime.R @@ -35,7 +35,7 @@ as.IDate.Date = function(x, ...) { as.IDate.POSIXct = function(x, tz = attr(x, "tzone", exact=TRUE), ...) { if (is.null(tz)) tz = "UTC" if (tz %chin% c("UTC", "GMT")) { - (setattr(as.integer(x) %/% 86400L, "class", c("IDate", "Date"))) # %/% returns new object so can use setattr() on it; wrap with () to return visibly + (setattr(as.integer(as.numeric(x) %/% 86400L), "class", c("IDate", "Date"))) # %/% returns new object so can use setattr() on it; wrap with () to return visibly } else as.IDate(as.Date(x, tz = tz, ...)) } @@ -305,7 +305,7 @@ as.POSIXlt.ITime = function(x, ...) { second = function(x) { if (inherits(x, 'POSIXct') && identical(attr(x, 'tzone', exact=TRUE), 'UTC')) { # if we know the object is in UTC, can calculate the hour much faster - as.integer(x) %% 60L + as.integer(as.numeric(x) %% 60L) } else { as.integer(as.POSIXlt(x)$sec) } @@ -313,7 +313,7 @@ second = function(x) { minute = function(x) { if (inherits(x, 'POSIXct') && identical(attr(x, 'tzone', exact=TRUE), 'UTC')) { # ever-so-slightly faster than x %% 3600L %/% 60L - as.integer(x) %/% 60L %% 60L + as.integer(as.numeric(x) %/% 60L %% 60L) } else { as.POSIXlt(x)$min } @@ -321,7 +321,7 @@ minute = function(x) { hour = function(x) { if (inherits(x, 'POSIXct') && identical(attr(x, 'tzone', exact=TRUE), 'UTC')) { # ever-so-slightly faster than x %% 86400L %/% 3600L - as.integer(x) %/% 3600L %% 24L + as.integer(as.numeric(x) %/% 3600L %% 24L) } else { as.POSIXlt(x)$hour } diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 8a308c19c8..736ff800bf 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -15827,6 +15827,14 @@ df1 = data.table(a=1:5, b=c(0, 0, 1, 0, 2)) df2 = data.table(c=c(1, 1, 2, 2, 3), d=c(3, 4, 3, 5, 4)) test(2092.3, copy(df2)[ , s := df1[.SD, on=.(a >= c, a <= d), sum(b), by=.EACHI]$V1], df2[ , s := c(1, 1, 1, 3, 1)]) + +# POSIXct overflow to NA before 1901 and after 2038, #3780 +date=as.POSIXct("1900-01-01", tz="UTC") +test(2093.1, as.IDate(date), as.IDate(-25567L)) +test(2093.2, hour(date), 0L) +test(2093.3, minute(date), 0L) +test(2093.4, second(date), 0L) + ################################### # Add new tests above this line #