You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言if_else语句处理时间字段返回异常值问题排查

问题描述

原始数据:

# A tibble: 6 × 3
  rowid Arrival             Depart             
  <int> <dttm>              <dttm>             
1     1 2023-02-11 07:00:00 2023-02-11 17:30:00
2     2 2023-02-13 10:00:00 2023-02-13 18:00:00
3     3 2023-02-14 08:00:00 2023-02-14 17:00:00
4     4 2023-02-15 08:00:00 2023-02-15 17:00:00
5     5 2023-02-16 08:00:00 2023-02-16 18:00:00
6     6 2023-02-18 07:00:00 2023-02-18 17:30:00

structure(list(rowid = 1:6, Arrival = structure(c(1676098800, 
1676282400, 1676361600, 1676448000, 1676534400, 1676703600), tzone = "UTC", class = c("POSIXct", 
"POSIXt")), Depart = structure(c(1676136600, 1676311200, 1676394000, 
1676480400, 1676570400, 1676741400), tzone = "UTC", class = c("POSIXct", 
"POSIXt"))), row.names = c(NA, -6L), class = c("tbl_df", "tbl", 
"data.frame"))

定义变量:

ri <- 2
int <- test_int[2]

其中int是一个interval:

> int
[1] 2023-02-13 06:00:00 EST--2023-02-13 13:00:00 EST

执行代码:

test <- test %>% mutate(
  interval_start = if_else(rowid == ri, int_start(int), Arrival),
  interval_end = if_else(rowid == ri, int_end(int), Depart)
) %>% select(Arrival, interval_start, Depart, interval_end)  

得到异常结果(非rowid=2的行,interval_start/interval_end显示时间比原Arrival/Depart早5小时):

# A tibble: 6 × 4
  Arrival             interval_start      Depart              interval_end       
  <dttm>              <dttm>              <dttm>              <dttm>             
1 2023-02-11 07:00:00 2023-02-11 02:00:00 2023-02-11 17:30:00 2023-02-11 12:30:00
2 2023-02-13 10:00:00 2023-02-13 06:00:00 2023-02-13 18:00:00 2023-02-13 13:00:00
3 2023-02-14 08:00:00 2023-02-14 03:00:00 2023-02-14 17:00:00 2023-02-14 12:00:00
4 2023-02-15 08:00:00 2023-02-15 03:00:00 2023-02-15 17:00:00 2023-02-15 12:00:00
5 2023-02-16 08:00:00 2023-02-16 03:00:00 2023-02-16 18:00:00 2023-02-16 13:00:00
6 2023-02-18 07:00:00 2023-02-18 02:00:00 2023-02-18 17:30:00 2023-02-18 12:30:00

structure(list(Arrival = structure(c(1676098800, 1676282400, 
1676361600, 1676448000, 1676534400, 1676703600), tzone = "UTC", class = c("POSIXct", 
"POSIXt")), interval_start = structure(c(1676098800, 1676286000, 
1676361600, 1676448000, 1676534400, 1676703600), class = c("POSIXct", 
"POSIXt")), Depart = structure(c(1676136600, 1676311200, 1676394000, 
1676480400, 1676570400, 1676741400), tzone = "UTC", class = c("POSIXct", 
"POSIXt")), interval_end = structure(c(1676136600, 1676311200, 
1676394000, 1676480400, 1676570400, 1676741400), class = c("POSIXct", 
"POSIXt"))), row.names = c(NA, -6L), class = c("tbl_df", "tbl", 
"data.frame"))
原因分析

dplyr::if_else对输出的类型和属性有严格一致性要求:

  • 原数据的Arrival/Depart是带UTC时区属性的POSIXct对象
  • int_start(int)/int_end(int)返回的是带EST时区的POSIXct对象
  • if_else会强制统一输出的时区属性,这里以第二个参数(int_start(int))的时区为准,导致非目标行的Arrival/Depart被转换为EST时区显示,时间戳本身未变化(看结构里的时间戳值和原数据一致),只是时区切换后显示时间早了5小时(UTC与EST的时差)。
解决方法

有三种可行方案:

方案1:统一两边的时区

将int_start(int)/int_end(int)转换为UTC时区后传入if_else:

test <- test %>% mutate(
  interval_start = if_else(rowid == ri, 
                          with_tz(int_start(int), tzone = "UTC"), 
                          Arrival),
  interval_end = if_else(rowid == ri, 
                        with_tz(int_end(int), tzone = "UTC"), 
                        Depart)
) %>% select(Arrival, interval_start, Depart, interval_end)

方案2:使用base::ifelse替代dplyr::if_else

base::ifelse不会严格强制属性一致,会保留原向量的时区属性:

test <- test %>% mutate(
  interval_start = ifelse(rowid == ri, int_start(int), Arrival),
  interval_end = ifelse(rowid == ri, int_end(int), Depart)
) %>% select(Arrival, interval_start, Depart, interval_end)

方案3:使用case_when

case_when在处理属性不一致的场景时更灵活:

test <- test %>% mutate(
  interval_start = case_when(rowid == ri ~ int_start(int), TRUE ~ Arrival),
  interval_end = case_when(rowid == ri ~ int_end(int), TRUE ~ Depart)
) %>% select(Arrival, interval_start, Depart, interval_end)

内容的提问来源于stack exchange,提问作者marcelklib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:45:32