使用lubridate进行向量化时区转换

6

我有一个包含日期时间字符串列的数据框:

library(tidyverse)
library(lubridate)

testdf = data_frame(
  mytz = c('Australia/Sydney', 'Australia/Adelaide', 'Australia/Perth'),
  mydt = c('2018-01-17T09:15:00', '2018-01-17T09:16:00', '2018-01-17T09:18:00'))

testdf

#  A tibble: 3 x 2
#   mytz               mydt
#   <chr>              <chr>
# 1 Australia/Sydney   2018-01-17T09:15:00
# 2 Australia/Adelaide 2018-01-17T09:16:00
# 3 Australia/Perth    2018-01-17T09:18:00

我希望将这些日期时间字符串转换为带有各自时区的POSIX日期时间对象:
testdf %>% mutate(mydt_new = ymd_hms(mydt, tz = mytz))

在 mutate_impl(.data, dots) 中出现错误: 评估时出现错误:tz 参数必须是单个字符字符串。 此外:警告消息: 在 if (tz != "UTC") { 中: 条件长度 > 1,只有第一个元素将被使用。

如果我在不带时区的情况下使用 ymd_hms 并将其传递到 force_tz 中,我会得到相同的结果。我们能否得出结论,lubridate 在时区操作方面不支持任何形式的向量化?


1
也许使用 testdf %>% rowwise %>% mutate(mydt_new = ymd_hms(mydt, tz = mytz)) - jazzurro
可以了!不过我不明白为什么需要使用 rowwise - jimjamslam
我想,如果它正在操作组,并且每个组只有一行,则在每次调用中 tz 仅为长度 1。即使我有多行具有相同的时区,这也可以工作。谢谢! - jimjamslam
如果您喜欢的话,很高兴将此作为接受的答案! - jimjamslam
1
好的。让我来处理。 - jazzurro
有趣的是,这个数据框 tibble 的输出显示出了新列在 Australia/Perth,尽管我处于 Australia/Sydney。我想知道这样的显示是否是随意的。 - jimjamslam
2个回答

5
另一个选择是map2。最好将不同的tz输出存储在一个list中,因为这样可能会被强制转换为单个tz
library(tidyverse)
out <- testdf %>%
         mutate(mydt_new = map2(mydt, mytz, ~ymd_hms(.x, tz = .y)))

如果需要的话,可以对其进行unnest
out %>%
   unnest

列表中的值为:
out %>%
   pull(mydt_new)
#[[1]]
#[1] "2018-01-17 09:15:00 AEDT"

#[[2]]
#[1] "2018-01-17 09:16:00 ACDT"

#[[3]]
#[1] "2018-01-17 09:18:00 AWST"

1
@rensa,这样做更好,因为该列仅允许单个时区,并且强制转换为单个时区可能会有所不同。 - akrun
1
@rensa 有趣的是,如果我使用 unnest,与 jazzuro 得到的值不同。 因此,它将强制转换为不同的 tz - akrun
1
如果我可以的话,我会接受你们两个的答案。但是我认为,作为一般情况,优先考虑输出的可预测性是一个好主意。 - jimjamslam
1
@akrun 感谢您的回复。很高兴听到您会做同样的事情。我会坚持这种方法。顺便说一下,您在这里仍然很出色。太棒了。我还有很多东西要向您学习。 - jazzurro
2
@akrun 我认为你是我声望的主要贡献者。非常感谢。 :) - jazzurro
显示剩余6条评论

3

tz argument must be a single character string. 表示在 ymd_hms() 中输入了多个时区。为了确保只有一个时区被输入到函数中,我使用了 rowwise()。请注意,我不在澳大利亚时区,所以我不确定我的结果是否与你的相同。

testdf <- data_frame(mytz = c('Australia/Sydney', 'Australia/Adelaide', 'Australia/Perth'),
                     mydt = c('2018-01-17 09:15:00', '2018-01-17 09:16:00', '2018-01-17 09:18:00'))

testdf %>% 
rowwise %>% 
mutate(mydt_new = ymd_hms(mydt, tz = mytz))

  mytz               mydt                mydt_new           
  <chr>              <chr>               <dttm>             
1 Australia/Sydney   2018-01-17 09:15:00 2018-01-17 06:15:00
2 Australia/Adelaide 2018-01-17 09:16:00 2018-01-17 06:46:00
3 Australia/Perth    2018-01-17 09:18:00 2018-01-17 09:18:00

@jazzurro,我将其发布为解决方案,因为它是关于时区如何被强制转换的有趣比较。希望你不介意。 - akrun
@akrun 最终,我解决了问题。看到差异后,我首先想知道我的代码是如何工作的。我以为我正在创建一个带有时区的日期对象(例如,悉尼的第一行)。然后我意识到结果显示了珀斯的时区。代码最初是否根据时区生成日期对象?我还有另一个问题,但这需要更多的打字。您有时间的时候,能聊聊吗? - jazzurro
1
如果我按照你的想法并执行以下操作:testdf %>% rowwise %>% mutate(mydt_new = format(ymd_hms(mydt, tz = mytz), usetz = TRUE)) - jazzurro
@akrun 是的,我也是这么认为的。只要结果保留在列表中,我们就看不到其中的内容。所以拥有这种类型的信息是一件好事。顺便说一下,由于时差,聊天可能会有困难。让我简要解释一下我的问题。就像这里的 OP 一样,我有过一些接收到 mutate() 错误消息的时刻。因为我现在不记得任何具体的案例,所以我无法提出任何特定的案例。在这些情况下,rowwise 是解决方法。你是否遇到过这种情况?我认为我缺少的关键是什么时候需要使用 rowwise。 - jazzurro
@akrun 不好意思,x和y参数的顺序颠倒了。那么在这里使用map2相比于经典的Map有什么优势呢? - jazzurro
显示剩余15条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接