R: if_else 和时区强制
R: if_else and timezone forcing
我有一个奇怪的问题(也许我遗漏了什么?),试图在 if_else
内强制时区(因为 ifelse
似乎不能很好地处理 POSIXct
) .好像只在TRUE
时才强制,FALSE
时才转换。为什么?如何解决?
library(lubridate)
library(dplyr)
some_date = ymd_hm("2020-06-01 17:45", tz = "America/New_York")
if_else(TRUE, force_tz(some_date, tz = "GMT"), force_tz(some_date, tz = "Singapore"))
[1] "2020-06-01 17:45:00 GMT"
if_else(FALSE, force_tz(some_date, tz = "GMT"), force_tz(some_date, tz = "Singapore"))
[1] "2020-06-01 09:45:00 GMT"
我希望得到与 运行 force_tz 相同的结果:
# if TRUE
force_tz(some_date, tz = "GMT")
[1] "2020-06-01 17:45:00 GMT"
# if FALSE
force_tz(some_date, tz = "Singapore")
[1] "2020-06-01 17:45:00 +08"
谢谢!
罪魁祸首在于dplyr::if_else
如何进行调整。
首先,我最初关于向量和 TZ 的评论仍然有效,并且仍然是这个问题的核心。备案:
When you're dealing with POSIXt
in a vector, the TZ is an attribute of the whole vector, not each independent element. This means that either (a) you must accept that all timestamps within a vector will have the same TZ; or (b) you need to adapt your process to deal with a list
of timestamps, in which case each time can have its own TZ.
如果你看if_else
:
function (condition, true, false, missing = NULL)
{
if (!is.logical(condition)) {
bad_args("condition", "must be a logical vector, not {friendly_type_of(condition)}")
}
out <- true[rep(NA_integer_, length(condition))]
用第一个 ("true") 向量的 NA
变体预填充 out
向量。 (这是必要的,因为R确实有至少6种NA
:逻辑(NA
),整数(NA_integer_
),real/float(NA_real_
),字符串 (NA_character_
)、日期 (c.Date(NA)
) 和时间 (c.POSIXct(NA)
);因此 如何 形成一个向量 NA
很重要。)但是,一旦 NA
s 的向量被预填充,就会意识到这是基于第一个向量,所以它的属性被带入 out
向量。
Sys.time()
# [1] "2020-06-01 09:02:06 PDT"
now <- Sys.time()
attr(now, "tzone") <- "GMT"
dput(now)
# structure(1591027335.41804, class = c("POSIXct", "POSIXt"), tzone = "GMT")
dput(now[NA])
# structure(NA_real_, class = c("POSIXct", "POSIXt"), tzone = "GMT")
(看看tzone=
怎么还是一样)。这意味着输出向量(在 POSIXt
个向量上运行时)will always carry forward the TZ of the
trueargument to
if_else`.
从这里开始,if_else
在 替换 中工作(使用其内部 replace_with
,实际上只是 out[condition] <- false[condition]
)。替换 不会 影响 TZ;事实上,false
时间的数字等价物在不考虑其 TZ 的情况下被同化。当然,false
向量的 "absolute time in the world" 被保留。
唯一的解决方法是更改您的工作流程以处理 POSIXt
的 list
而不是向量。 if_else
仍然在那里工作。
now
# [1] "2020-06-01 16:02:15 GMT"
now1 <- list(now, now+1) ; now2 <- list(now+86400, now+86401)
now1
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-01 16:02:16 GMT"
now2
# [[1]]
# [1] "2020-06-02 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 16:02:16 GMT"
attr(now1[[2]], "tzone") <- "Singapore"
attr(now2[[2]], "tzone") <- "US/Pacific"
now1
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 00:02:16 +08"
now2
# [[1]]
# [1] "2020-06-02 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 09:02:16 PDT"
if_else(c(TRUE, FALSE), now1, now2)
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 09:02:16 PDT"
我有一个奇怪的问题(也许我遗漏了什么?),试图在 if_else
内强制时区(因为 ifelse
似乎不能很好地处理 POSIXct
) .好像只在TRUE
时才强制,FALSE
时才转换。为什么?如何解决?
library(lubridate)
library(dplyr)
some_date = ymd_hm("2020-06-01 17:45", tz = "America/New_York")
if_else(TRUE, force_tz(some_date, tz = "GMT"), force_tz(some_date, tz = "Singapore"))
[1] "2020-06-01 17:45:00 GMT"
if_else(FALSE, force_tz(some_date, tz = "GMT"), force_tz(some_date, tz = "Singapore"))
[1] "2020-06-01 09:45:00 GMT"
我希望得到与 运行 force_tz 相同的结果:
# if TRUE
force_tz(some_date, tz = "GMT")
[1] "2020-06-01 17:45:00 GMT"
# if FALSE
force_tz(some_date, tz = "Singapore")
[1] "2020-06-01 17:45:00 +08"
谢谢!
罪魁祸首在于dplyr::if_else
如何进行调整。
首先,我最初关于向量和 TZ 的评论仍然有效,并且仍然是这个问题的核心。备案:
When you're dealing with
POSIXt
in a vector, the TZ is an attribute of the whole vector, not each independent element. This means that either (a) you must accept that all timestamps within a vector will have the same TZ; or (b) you need to adapt your process to deal with alist
of timestamps, in which case each time can have its own TZ.
如果你看if_else
:
function (condition, true, false, missing = NULL)
{
if (!is.logical(condition)) {
bad_args("condition", "must be a logical vector, not {friendly_type_of(condition)}")
}
out <- true[rep(NA_integer_, length(condition))]
用第一个 ("true") 向量的 NA
变体预填充 out
向量。 (这是必要的,因为R确实有至少6种NA
:逻辑(NA
),整数(NA_integer_
),real/float(NA_real_
),字符串 (NA_character_
)、日期 (c.Date(NA)
) 和时间 (c.POSIXct(NA)
);因此 如何 形成一个向量 NA
很重要。)但是,一旦 NA
s 的向量被预填充,就会意识到这是基于第一个向量,所以它的属性被带入 out
向量。
Sys.time()
# [1] "2020-06-01 09:02:06 PDT"
now <- Sys.time()
attr(now, "tzone") <- "GMT"
dput(now)
# structure(1591027335.41804, class = c("POSIXct", "POSIXt"), tzone = "GMT")
dput(now[NA])
# structure(NA_real_, class = c("POSIXct", "POSIXt"), tzone = "GMT")
(看看tzone=
怎么还是一样)。这意味着输出向量(在 POSIXt
个向量上运行时)will always carry forward the TZ of the
trueargument to
if_else`.
从这里开始,if_else
在 替换 中工作(使用其内部 replace_with
,实际上只是 out[condition] <- false[condition]
)。替换 不会 影响 TZ;事实上,false
时间的数字等价物在不考虑其 TZ 的情况下被同化。当然,false
向量的 "absolute time in the world" 被保留。
唯一的解决方法是更改您的工作流程以处理 POSIXt
的 list
而不是向量。 if_else
仍然在那里工作。
now
# [1] "2020-06-01 16:02:15 GMT"
now1 <- list(now, now+1) ; now2 <- list(now+86400, now+86401)
now1
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-01 16:02:16 GMT"
now2
# [[1]]
# [1] "2020-06-02 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 16:02:16 GMT"
attr(now1[[2]], "tzone") <- "Singapore"
attr(now2[[2]], "tzone") <- "US/Pacific"
now1
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 00:02:16 +08"
now2
# [[1]]
# [1] "2020-06-02 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 09:02:16 PDT"
if_else(c(TRUE, FALSE), now1, now2)
# [[1]]
# [1] "2020-06-01 16:02:15 GMT"
# [[2]]
# [1] "2020-06-02 09:02:16 PDT"