2013-02-22 12 views
6

Sto lavorando con dati .csv esportati da Teradata. Diverse colonne erano in origine timestamp con fusi orari, quindi dopo aver caricato il file .csv in R mi piacerebbe convertire queste colonne (che sono caricate come stringhe) in POSIXlt o POSIXct. Sto usando strptime, ma il formato del fuso orario dal file .csv non corrisponde a quello che si aspetta strptime. Ad esempio, si aspetta -0400 ma il formato .csv ha il formato -04:00 in cui i due punti separano le ore ei minuti.Utilizzo di strptime% z con formato di fuso orario speciale

Posso rimuovere i due punti, ma questo è un ulteriore passaggio e complicazione che vorrei evitare se possibile. C'è un modo per dire a strptime di utilizzare un formato diverso per il fuso orario (%z)?

Ecco un esempio:

## 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" 

Così sto cercando di ottenere quest'ultimo risultato usando qualcosa come strptime(x,"%Y-%m-%d %H:%M:%OS%zz"), dove %zz è un'espressione personalizzata per il fuso orario che riconosce il formato -04:00. O %zH:%zM potrebbe essere ancora meglio.

Se questo non è possibile, qualcuno ha una funzione slick/flessibile per convertire stringhe (di vari formati) in date per più colonne di un data.frame/data.table?

risposta

3

Si scopre lubridate in grado di gestire questo formato:

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

Oppure, per visualizzare nel fuso orario locale:

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

Per una maggiore flessibilità (ancora utilizzando lubridate):

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

Per velocità più veloce (tra lubridate opzioni):

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

Timings:

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

Ho appena trovato questa domanda cercando di ottenere la stessa cosa.

L'unica cosa che ho trovato per risolvere il problema è usare regex per rimuovere i due punti, come hai menzionato. È possibile stringere leggermente la regex per evitare di commettere errori nella sostituzione.

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

E 'il 2016 e il mondo è ancora avere a che fare con questo ... – sehe

Problemi correlati