将具有多个时区的大型数据集的本地日期时间转换为UTC

时间:2019-07-01 23:43:53

标签: r timezone utc

我得到了一个包含纬度,经度,本地日期和本地时间字段的海量数据集。我正在尝试将此信息组织到ISO UTC时间字段中。我的代码有问题,因为当数据中存在多个时区时,我不知道如何使用as.POSIXct()。每当我尝试在tz =部分中使用数组或循环时,都会收到错误消息。

我使用了lutz包中的tz_lookup_coords()函数来定义数据帧中每一行的时区。我还能够将数据过滤到单个时区,并成功使用as.POSIXct()和format()函数获取UTC时间。但是,我想要一个更优雅的解决方案,将单个代码应用于整个数据集。

sample<- data.frame(
  "localDate" = c("2015-04-20","2016-07-17","2015-08-06"), 
  "localTime" = c("14:00", "14:46", NA ), 
  "timeZone" = c("Pacific/Pago_Pago", NA , "Pacific/Honolulu")
)

# Change times from local to UTC
sample$localDateTime <- paste(sample$localDate, sample$localTime, sep = " ")
for (i in 1:nrow(sample)) {
  sample[i,]$localDateTime <- as.POSIXct(sample[i,]$localDateTime, tz= sample[i,]$timeZone, "%Y-%m-%d %H:%M")
}
sample$eventDate <- format(sample$localDateTime, tz= "UTC", usetz = TRUE)

当我输入“太平洋/檀香山”之类的单个时区时,代码可以很好地工作,但它将每一行都当作一个时区来对待。

> sample
   localDate localTime          timeZone    localDateTime               eventDate
1 2015-04-20     14:00 Pacific/Pago_Pago 2015-04-20 14:00 2015-04-21 00:00:00 UTC
2 2016-07-17     14:46    Pacific/Saipan 2016-07-17 14:46 2016-07-18 00:46:00 UTC
3 2015-08-06     10:35  Pacific/Honolulu 2015-08-06 10:35 2015-08-06 20:35:00 UTC

如果我尝试在函数的tz =部分中使用除引号中的字符串以外的其他字符,则会收到以下代码:

Error in strptime(x, format, tz = tz) : invalid 'tz' value

2 个答案:

答案 0 :(得分:0)

library(lubridate)

sample <- 
  data.frame(
     "localDate" = c("2015-04-20","2016-07-17","2015-08-06"), 
     "localTime" = c("14:00", "14:46", "10:35"), 
     "timeZone" = c("Pacific/Pago_Pago", "Pacific/Saipan", "Pacific/Honolulu")
   )

sample$localDateTime <- 
  paste(sample$localDate, sample$localTime, sep = " ")

list <- 
  list()

for (i in 1:nrow(sample)){
     list[[i]] <- 
       ymd_hm(sample$localDateTime[i], 
              tz = as.character(sample$timeZone[i]))
   }

list   

R> list
[[1]]
[1] "2015-04-20 14:00:00 SST"

[[2]]
[1] "2016-07-17 14:46:00 ChST"

[[3]]
[1] "2015-08-06 10:35:00 HST"

答案 1 :(得分:0)

该错误是由于timeZone列是一个因素而不是字符向量,请在定义data.frame时使用stringsAsFactors = FALSEtimeZone指定为字符列。您还可以通过使用lubridate包中的矢量化函数来避免任何循环:

library(lubridate)

df <- data.frame(
    "localDate" = c("2015-04-20","2016-07-17","2015-08-06"), 
    "localTime" = c("14:00", "14:46", "10:35"), 
    "timeZone" = c("Pacific/Pago_Pago", "Pacific/Saipan", "Pacific/Honolulu"),
    stringsAsFactors = FALSE
)

df$eventDate <- force_tzs(ymd_hm(with(df, paste(localDate, localTime))), tzones = df$timeZone)

df
#>    localDate localTime          timeZone           eventDate
#> 1 2015-04-20     14:00 Pacific/Pago_Pago 2015-04-21 01:00:00
#> 2 2016-07-17     14:46    Pacific/Saipan 2016-07-17 04:46:00
#> 3 2015-08-06     10:35  Pacific/Honolulu 2015-08-06 20:35:00

编辑:如果缺少值,请检查每一行是否可以转换,如果不能返回NA。下面是使用基数R的示例解决方案:

df <- data.frame(
    "localDate" = c("2015-04-20","2016-07-17","2015-08-06", "2019-01-01", "2019-01-01"), 
    "localTime" = c("14:00", "14:46", "10:35", NA, "00:00"), 
    "timeZone" = c("Pacific/Pago_Pago", "Pacific/Saipan", "Pacific/Honolulu", 
        "Pacific/Honolulu", NA),
    stringsAsFactors = FALSE
)

df$eventDate <- apply(df, 1, function(row) {     
      ifelse(any(is.na(row)), NA_character_,
          format(as.POSIXct(paste(row["localDate"], row["localTime"]), "%Y-%m-%d %H:%M",
              tz = row["timeZone"]), tz = "UTC", usetz = TRUE)
      )
    })
df   
#>    localDate localTime          timeZone               eventDate
#> 1 2015-04-20     14:00 Pacific/Pago_Pago 2015-04-21 01:00:00 UTC
#> 2 2016-07-17     14:46    Pacific/Saipan 2016-07-17 04:46:00 UTC
#> 3 2015-08-06     10:35  Pacific/Honolulu 2015-08-06 20:35:00 UTC
#> 4 2019-01-01      <NA>  Pacific/Honolulu                    <NA>
#> 5 2019-01-01     00:00              <NA>                    <NA>