diff --git a/NAMESPACE b/NAMESPACE index 2ffd29800..2787dc83f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -327,6 +327,7 @@ S3method(vec_proxy_order,array) S3method(vec_proxy_order,default) S3method(vec_proxy_order,list) S3method(vec_proxy_order,raw) +S3method(vec_ptype,POSIXlt) S3method(vec_ptype2,AsIs) S3method(vec_ptype2,Date) S3method(vec_ptype2,POSIXct) diff --git a/R/type-date-time.R b/R/type-date-time.R index 24e59b849..867d437c1 100644 --- a/R/type-date-time.R +++ b/R/type-date-time.R @@ -133,6 +133,22 @@ vec_ptype_abbr.difftime <- function(x, ...) { "drtn" } +# Ptype ------------------------------------------------------------------- + +#' @export +vec_ptype.POSIXlt <- function(x, ...) { + # `vec_ptype2()` pushes towards `POSIXct`. In theory, maybe `vec_ptype()` + # should as well so that `vec_c()` and `vec_c(, )` + # are consistent and both return `POSIXct`. In practice this broke a number of + # packages (datetimeoffset, slider, nanoarrow), and also generally means that + # you wouldn't be able to provide a `POSIXlt` as a `ptype` argument to + # anything and expect it to return a `POSIXlt` as output. So we've decided to + # just leave this inconsistency. Getting `POSIXlt` attributes exactly right + # is very tricky, and very R version dependent, so we just consistency align + # with `[` here and in tests. + x[0] +} + # Coerce ------------------------------------------------------------------ #' @rdname new_date diff --git a/tests/testthat/test-type-date-time.R b/tests/testthat/test-type-date-time.R index bd108a70d..b08c5d533 100644 --- a/tests/testthat/test-type-date-time.R +++ b/tests/testthat/test-type-date-time.R @@ -146,7 +146,18 @@ test_that("tz comes from first non-empty", { expect_identical(vec_ptype2(z, y), z[0]) }) -test_that("POSIXlt always steered towards POSIXct", { +test_that("POSIXlt remains POSIXlt in vec_ptype()", { + # See `vec_ptype.POSIXlt()` for details + x <- as.POSIXlt("2020-01-01", tz = "UTC") + exp <- x[0] + expect_identical(vec_ptype(x), exp) + + x <- as.POSIXlt("2020-01-01", tz = "America/New_York") + exp <- x[0] + expect_identical(vec_ptype(x), exp) +}) + +test_that("POSIXlt always steered towards POSIXct in vec_ptype2()", { dtc <- as.POSIXct("2020-01-01", tz = "UTC") dtl <- as.POSIXlt("2020-01-01", tz = "UTC") @@ -192,6 +203,27 @@ test_that("vec_ptype2() standardizes duration storage type to double", { expect_identical(vec_ptype2(x, x), expect) }) +test_that("vec_ptype_common() gives expected results with ", { + # See `vec_ptype.POSIXlt()` for details + x <- as.POSIXlt("2020-01-01", tz = "UTC") + + # `vec_ptype(x)` returns `` + exp <- x[0] + expect_identical(vec_ptype_common(x), exp) + expect_identical(vec_ptype_common(.ptype = x), exp) + + # `vec_ptype2(x, x)` returns `` + exp <- new_datetime(tzone = "UTC") + expect_identical(vec_ptype_common(x, x), exp) + + # With input, still uses `vec_ptype(x)`, so returns `` + exp <- x[0] + expect_identical(vec_ptype_common(x, NA), exp) + expect_identical(vec_ptype_common(NA, x), exp) + expect_identical(vec_ptype_common(x, NULL), exp) + expect_identical(vec_ptype_common(NULL, x), exp) +}) + # cast: dates --------------------------------------------------------------- test_that("safe casts work as expected", {