Code that works: duration
and period
objects
The following code successfully produces a duration
object and a period
object respectively.
> lubridate::as.duration(1)
[1] "1s"
> lubridate::seconds(1)
[1] "1S"
Code that doesn't work: duration
and period
objects in tibble
s
However, when I try to create tibble
s using a duration
or a period
object, I get uninformative error messages.
> tibble::tibble(y = lubridate::as.duration(1))
Error: Incompatible duration classes (Duration, numeric). Please coerce with `as.duration`.
> tibble::tibble(y = lubridate::seconds(1))
Error in x < 0 : cannot compare Period to Duration:
coerce with 'as.numeric' first.
Code that works: duration
and period
objects in data.frame
s
Replacing tibble::tibble
with base::data.frame
works.
> data.frame(y = lubridate::as.duration(1))
y
1 1s
> data.frame(y = lubridate::seconds(1))
y
1 1S
Code that doesn't work - coercing these data.frame
s to tibbles
Using tibble::as_tibble
to coerce these data.frame
s to tibbles
yields the same error as before.
> tibble::as_tibble(data.frame(y = lubridate::as.duration(1)))
Error: Incompatible duration classes (Duration, numeric). Please coerce with `as.duration`.
> tibble::as_tibble(data.frame(y = lubridate::seconds(1)))
Error in x < 0 : cannot compare Period to Duration:
coerce with 'as.numeric' first.
Possible explanation
Hadley mentions something in this Github issue - https://github.com/tidyverse/tibble/issues/326 - about S4 columns, which include as.duration
and as.period
. Nothing is specifically mentioned about incompatibility.
Digging in the source code, I find the following chain of dependencies that give the same error message: as_tibble.data.frame --> list_to_tibble --> new_tibble
In tibble:::list_to_tibble
, the only argument passed to tibble::new_tibble
is x
. Consequently, subclass
is assigned the default value of NULL
, and the penultimate line of tibble::new_tibble
becomes
class(x) <- c("tbl_df", "tbl", "data.frame")
The objects have a structure, but trying to call them directly yields an error.
> x <- data.frame(y = lubridate::as.duration(1))
> class(x) <- c("tbl_df", "tbl", "data.frame")
> str(x)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 1 obs. of 1 variable:
$ x:Formal class 'Duration' [package "lubridate"] with 1 slot
.. ..@ .Data: num 1
> x
Error: Incompatible duration classes (Duration, numeric). Please coerce with `as.duration`.
> x <- data.frame(y = lubridate::seconds(1))
> class(x) <- c("tbl_df", "tbl", "data.frame")
> str(x)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 1 obs. of 1 variable:
$ y:Formal class 'Period' [package "lubridate"] with 6 slots
.. ..@ .Data : num 1
.. ..@ year : num 0
.. ..@ month : num 0
.. ..@ day : num 0
.. ..@ hour : num 0
.. ..@ minute: num 0
> x
Error in x < 0 : cannot compare Period to Duration:
coerce with 'as.numeric' first.
Consequently, it appears that assigning the class of the data.frame
x
the vector c("tbl_df", "tbl", "data.frame")
causes R
to try to coerce x
in a way that throws an error.
Furthermore, given that tibble::tibble
also calls as_tibble
(albeit not on a data.frame
), I would hazard a guess that my issues with tibble::tibble
have the same cause.
Package versions
- Tibble: 1.4.1
- Lubridate: 1.7.1
- R: 3.4.3