5

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 tibbles

However, when I try to create tibbles 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.frames

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.frames to tibbles

Using tibble::as_tibble to coerce these data.frames 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
  • 3
    Another R user encountered the same problem and opened an issue on Github: https://github.com/tidyverse/tibble/issues/358. Leaving the question unanswered for now, as Hadley hasn't responded to the issue yet. –  Jan 13 '18 at 23:43

1 Answers1

3

This issue is now resolved as of pillar v.1.2.1 (https://github.com/r-lib/pillar/issues/88).