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

问题描述

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

有趣的是,当我在true中反转测试(并更改falseif_else()参数)时,结果会有所不同。

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

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_)生成缺少的datetime对象,并在代码中而不是as.POSIXct()中使用它。

R> NA_datetime_ <- parse_datetime(NA_character_)

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

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

$B
[1] "UTC"

$C
[1] "UTC"

解决方法

首先,您需要知道parse_datetime()返回一个日期时间对象,该对象的tzone属性默认为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属性,因此A的{​​{1}}被删除并重置为您所在地区的时区。实际上,tzone是两个小时后 不是 这三列的时间相等,但时区不相等。要解决此问题,您可以将C调整为拥有as.POSIXct(NA)属性,即将其替换为

tzone

注意: 您必须使用as.POSIXct(NA_character_,tz = "UTC") 而不是NA_character_,因为{{1}中的NA参数}仅适用于角色对象。


最后,将您的代码修改为

tz

记住要检查他们的时区。

as.POSIXct()
,

这是时区问题:

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