2017-04-05 70 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過濾掉了。您可以嘗試其他方法來找到更接近的匹配(可能先查找完全匹配,然後再查找開始/結束)。