2013-02-22 124 views
6

我正在使用从Teradata导出的.csv数据。几列最初是带时区的时间戳,所以在R中加载.csv之后,我想将这些列(它们作为字符串加载)转换为POSIXlt或POSIXct。我正在使用strptime,但.csv文件中的时区格式与strptime所期望的格式不匹配。例如,它期望-0400,但.csv的格式为-04:00,冒号分隔小时和分钟。以特殊时区格式使用strptime%z

我可以删除冒号,但这是一个额外的步骤和并发症,我想尽量避免。有没有办法告诉strptime使用不同的时区格式(%z)?

下面是一个例子:

## Example data: 
x <- c("2011-10-12 22:17:13.860746-04:00", "2011-10-12 22:17:13.860746+00:00") 
format <- "%Y-%m-%d %H:%M:%OS%z" 

## Doesn't work: 
strptime(x,format) 
## [1] NA NA 

## Ignores the timezone: 
as.POSIXct(x) 
## [1] "2011-10-12 22:17:13 EDT" "2011-10-12 22:17:13 EDT" 

## Remove the last colon: 
x2 <- gsub("(.*):", "\\1", x) 
x2 
## [1] "2011-10-12 22:17:13.860746-0400" "2011-10-12 22:17:13.860746+0000" 

## This works, but requires extra processing (removing the colon) 
strptime(x2,format) 
## [1] "2011-10-12 22:17:13" "2011-10-12 18:17:13" 

所以我希望获得使用类似strptime(x,"%Y-%m-%d %H:%M:%OS%zz"),其中%zz是承认的-04:00格式的时区自定义表达式这最后的结果。或者%zH:%zM可能会更好。

如果这是不可能的,是否有人有一个光滑/灵活的函数用于将字符串(各种格式)转换为data.frame/data.table的多列日期?

回答

3

原来lubridate可以处理这种格式:

library(lubridate) 
ymd_hms(x) 
## [1] "2011-10-13 02:17:13 UTC" "2011-10-12 22:17:13 UTC" 

或者,在本地时区显示:

with_tz(ymd_hms(x)) 
## [1] "2011-10-12 22:17:13 EDT" "2011-10-12 18:17:13 EDT" 

更多的灵活性(仍在使用lubridate):

parse_date_time(x, "%Y-%m-%d %H:%M:%OS%z") 

为了更快的速度(除lubridate选项):

lubridate:::.strptime(x, "%Y-%m-%d %H:%M:%OS%OO") 

时序:

microbenchmark(
    ymd_hms(x), 
    parse_date_time(x, "%Y-%m-%d %H:%M:%OS%z"), 
    lubridate:::.strptime(x, "%Y-%m-%d %H:%M:%OS%OO"), 
    strptime(gsub("(.*):", "\\1", x), format) 
) 

## Unit: microseconds 
##            expr  min  lq  mean median  uq  max neval 
##           ymd_hms(x) 1523.819 1578.495 1715.14577 1629.5385 1744.3695 2850.393 100 
##   parse_date_time(x, "%Y-%m-%d %H:%M:%OS%z") 1108.676 1150.633 1273.77301 1190.3315 1264.8050 5947.204 100 
## lubridate:::.strptime(x, "%Y-%m-%d %H:%M:%OS%OO") 89.838 103.390 112.45338 107.8425 115.2265 216.512 100 
##  strptime(gsub("(.*):", "\\\\1", x), format) 46.716 58.294 71.90934 69.9415 86.5860 105.044 100 
2

我刚刚遇到了这个问题,试图实现同样的事情。

我发现修复它的唯一方法是使用正则表达式去除冒号,就像你刚才提到的那样。您可以稍微拧紧正则表达式以避免替换时出错。

x2 <- gsub('^([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]+[+-][0-9]{2}):([0-9]{2})$', 
      '\\1\\2', 
      x) 
# [1] "2011-10-12 22:17:13.860746-0400" "2011-10-12 22:17:13.860746+0000" 
+4

这是2016年世界仍然必须处理这个... – sehe 2016-07-09 23:22:06