dplyr::if_else 更改日期时间 (POSIXct) 值

dplyr::if_else changes datetime (POSIXct) values

我正在处理一个包含大量时间戳的数据集。我尝试识别并设置为 NA 的一些无效时间戳。因为 if_else() 强制我的双臂具有相同的数据类型,所以我使用 as.POSIXct(NA) 来编码这些缺失值。

有趣的是,当我在 if_else().

中反转测试(并更改 truefalse 参数时,结果不同

下面是一些代码来说明我的问题:

x <- tibble(
  A = parse_datetime("2020-08-18 19:00"),
  B = if_else(TRUE,               A, as.POSIXct(NA)),
  C = if_else(FALSE, as.POSIXct(NA),              A)
)

> x
# A tibble: 1 x 3
  A                   B                   C                  
  <dttm>              <dttm>              <dttm>             
1 2020-08-18 19:00:00 2020-08-18 19:00:00 2020-08-18 21:00:00

知道吗,为什么 C 晚了两个小时?

跟进:

基于下面的好答案,我认为一个更具可读性的解决方案或许应该使用 parse_datetime(NA_character_) 生成一个缺失的日期时间对象,并在代码中使用它而不是 as.POSIXct().

R> NA_datetime_ <- parse_datetime(NA_character_)

R> x <- tibble(
  A = parse_datetime("2020-08-18 19:00"),
  B = if_else(TRUE,             A, NA_datetime_),
  C = if_else(FALSE, NA_datetime_,            A)
)

R> map(x, lubridate::tz)
$A
[1] "UTC"

$B
[1] "UTC"

$C
[1] "UTC"

这是一个时区问题:

lubridate::tz(x$A)
[1] "UTC"
lubridate::tz(x$B)
[1] "UTC"
lubridate::tz(x$C)
[1] ""

这是由于 if_else <- function (test, yes, no) 的工作方式:它使用 yes 参数的属性,对于 C 来说是 NA.

首先,您需要知道 parse_datetime() returns 具有 tzone 属性的 date-time object 默认为 UTC。您可以使用 lubridate::tz(x$A)attributes(x$A) 来检查它。

if_else()的文档中,它说truefalse参数必须是同一类型。 所有其他属性取自true。因此,部分 C 你的小标题:

C = if_else(FALSE, as.POSIXct(NA), A)

as.POSIXct(NA) 没有 tzone 属性,因此 Atzone 被删除并重置为您所在地区的时区。实际上,C 而不是 两个小时后。 三列时间相等但时区不相等。要修复它,您可以将as.POSIXct(NA)调整为拥有一个tzone属性,即替换为

as.POSIXct(NA_character_, tz = "UTC")

注意: 您必须使用 NA_character_ 而不是 NA 因为 tz as.POSIXct() 中的参数仅适用于字符 objects.


最后,修改你的代码为

x <- tibble(
  A = parse_datetime("2020-08-18 19:00"),
  B = if_else(TRUE, A, as.POSIXct(NA_character_, tz = "UTC")),
  C = if_else(FALSE, as.POSIXct(NA_character_, tz = "UTC"), A)
)

# # A tibble: 1 x 3
#   A                   B                   C                  
#   <dttm>              <dttm>              <dttm>             
# 1 2020-08-18 19:00:00 2020-08-18 19:00:00 2020-08-18 19:00:00

记得检查他们的时区。

R > lubridate::tz(x$A)
[1] "UTC"
R > lubridate::tz(x$B)
[1] "UTC"
R > lubridate::tz(x$C)
[1] "UTC"