2017-04-05 26 views
0

我有这些以日期在数据帧,我想增加一列,是时区如何提取时区与POSIXct列日期

d = data.frame(dates = c(as.POSIXct("2017-01-01 PDT"), as.POSIXct("2017-04-02 PST"))) 
d$TZ = attr(as.POSIXlt(d$dates), "tzone") ### this doesn't do anything 
d 

,当我尝试使用添加时区:d$TZ = attr(as.POSIXlt(d$dates), "tzone")我得到这个错误:

> d$TZ = attr(as.POSIXlt(d$dates), "tzone") 
Error in `$<-.data.frame`(`*tmp*`, "TZ", value = c("", "PST", "PDT")) : 
    replacement has 3 rows, data has 2 

我想输出是:

 dates TZ 
1 2017-01-01 PDT 
2 2017-04-02  PST 

回答

2

2017-01-01不应该是PDT,夏令时是错误的。这就是为什么如果你看看d$dates,你会发现你的时区显然是颠倒的:R是“解决问题”(即使你不希望它)。有人可能会尝试使用format=...参数到as.POSIXct,但输入时不存在%-代码,因此没有帮助。

此外,d$dates显示时区的事实是因为R在分析时间时认真(/不小心?)假定您的本地时区。这可以通过更改日期的一个UTC显示:

d = data.frame(dates = c(as.POSIXct("2017-01-01 PDT"), as.POSIXct("2017-04-02 UTC"))) 
d$dates 
# [1] "2017-01-01 PST" "2017-04-02 PDT" 
#         ^^^ is not UTC 

此外,R似乎并不明白"PDT"作为一个时区:

as.POSIXct("2017-01-01", tz = "PDT") 
# ... lots of warnings ... 
# [1] "2017-01-01 GMT" 

接受类似的东西:

as.POSIXct("2017-01-01", tz = "PST8PDT") 
# [1] "2017-01-01 PST" 

如果你真的想要的是从原始字符串的字面部分,那么只需d$TZ <- gsub(".* ", "", d$dates)会给你,但如果你的意图不是美容/印刷,这些可能并不全都被R识别。你可能需要翻译成“已知”的东西。

一种方法是将源更改为使用小时偏移而不是时区(例如,-0800而不是PDT)。这样做,你可以分析它:(我假设,因为你正在使用as.POSIXct副想要的日期/时间标记,不只是一个日期as.Date

as.POSIXct("2017-01-01 -0500", format = "%Y-%m-%d %z") 
# [1] "2016-12-31 21:00:00 PST" 
as.POSIXct("2017-01-01 -0500", format = "%Y-%m-%d %z", tz = "UTC") 
# [1] "2017-01-01 05:00:00 UTC" 

另一种方法是在已知时区列表中翻译建议的时区。您可以通过?timezones(另一个相关Q/A here)找到已知时区。

一个小测试之后(请测试这个进一步的),我想出了这个:

converttz <- function(x) { 
    on <- OlsonNames() 
    ind <- sapply(gsub(".* ", "", x), function(z) head(grep(z, on), n = 1)) 
    ret <- character(length(x)) 
    ret[lengths(ind) == 0] <- NA 
    ret[lengths(ind) > 0] <- on[unlist(ind[lengths(ind) > 0])] 
    ret 
} 

这工作只要情况下是正确的;也就是说,"est"可能与"America/Creston"一样容易匹配,即使您只在字符串的开头或结尾进行搜索,它仍然可以匹配"Europe/Budapest"

从这里,像这样的工作:

dts <- c("2017-01-01 PDT", "2017-04-02 UTC") 
d <- data.frame(dates = as.POSIXct(dts), stringsAsFactors = FALSE) 
d$TZ <- converttz(dts) 
str(d) 
# 'data.frame': 2 obs. of 2 variables: 
# $ dates: POSIXct, format: "2017-01-01" "2017-04-02" 
# $ TZ : chr "PST8PDT" "Etc/UTC" 

好了,"Etc/UTC"不是很悦目。 "UTC"确实存在,但它是第二个匹配的,因此被head过滤掉了。您可以尝试其他方法来找到更接近的匹配(可能先查找完全匹配,然后再查找开始/结束)。