我正在尝试使用lubridate::force_tz将时区信息添加到格式化为字符串(如.character())的时间戳(日期+时间)中。两者都存储为数据帧中的两列:
require(lubridate)
require(dplyr)
row1<-c(as.character(now()),"Etc/UTC")
row2<-c(as.character(now()+5),"America/Chicago")
df<-as.data.frame(rbind(row1,row2))
names(df)<-c("dt","tz")
x<-force_tz(as.POSIXct(as.character(now())),"Etc/UTC") #works
df<-df%>%mutate(newDT=force_tz(as.POSIXct(dt),tz)) #fails
我得到:UseMethod中的错误("mute_"):没有适用于类"c('matrix','character')"对象的"mutate_"方法
根据Stibu的评论,我尝试了一种迭代的(类似un-R的)方法:
for (i in seq(from=1,to=length(df$dt))){
timestamp<-as.character(df[i,1])
tz<-as.character(df[i,2])
print(tz)
newdt<-force_tz(as.POSIXct(timestamp),tz)
df[i,3]<-newdt
print(attr(df[i,3],"tzone"))
df$timezone<-attr(df[i,3],"tzone")
}
这样可以正确地提取值,但似乎会将tz的值设置为遇到的第一个值——奇怪的是:
[1] "Etc/UTC"
[1] "Etc/UTC"
[1] "America/Chicago"
[1] "Etc/UTC"
我本以为最后一次打印输出会产生"America/Chicago"
df看起来像:
> df
dt tz newDT timezone
1 2016-04-13 23:07:45 Etc/UTC 2016-04-13 23:07:45 Etc/UTC
2 2016-04-13 23:07:50 America/Chicago 2016-04-14 04:07:50 Etc/UTC
您的代码中实际上有两个问题,我将在下面分别讨论。
dplyr处理数据帧
您的df
是一个矩阵,而不是一个数据帧。但是mutate()
(以及dplyr的函数)适用于数据帧。错误消息只是简单地告诉您mutate()
不知道如何处理矩阵。
您可以通过将df
转换为数据帧来解决此问题:
df <- as.data.frame(df)
names(df)<-c("dt","tz")
关于names()
的备注:此函数可用于获取/设置数据帧的列名。对于矩阵,对应的函数是colnames()
。您在矩阵上使用了names()
,它没有设置矩阵的列名。因此,在转换之后也不设置数据帧的名称。
您也可以从一开始创建一个数据帧,如下所示:
df <- data.frame(dt = as.character(c(now(), now() + 5)),
tz = c("Etc/UTC", "America/Chicago"),
stringsAsFactors = FALSE)
请注意,您需要按列定义内容,而不是像以前那样按行定义内容。
如果使用数据帧df
,则mutate()
不会出现错误。
每个矢量一个时区
不幸的是,还有第二个问题。你想做的事根本做不到。原因如下。
让我们用时区CET
:将df
的第一列转换为POSIXct
ts <- as.POSIXct(df$dt, tz = "CET")
ts
## [1] "2016-04-13 14:42:26 CEST" "2016-04-13 14:42:31 CEST"
让我们试着用两个时区做同样的事情:
ts <- as.POSIXct(df$dt, tz = c("CET", "UTC"))
## Error in strptime(xx, f <- "%Y-%m-%d %H:%M:%OS", tz = tz) :
## invalid 'tz' value
这不起作用。原因是每个向量有一个单个时区,而不是向量中每个元素都有一个时区。查看ts
:的属性
attributes(ts)
## $class
## [1] "POSIXct" "POSIXt"
##
## $tzone
## [1] "CET"
时区被设置为整个向量的属性,而不是每个元素的属性。