如何将数据框列中的所有日期时间转换为 R 中的特定日期时间格式(当 csv 文件以不同格式存储它们时)

how to convert all datetimes in a dataframe column into a particular datetime format in R (when the csv file has stored them in different formats)

这似乎是一个愚蠢的问题,但它让我花了好几天的时间首先确定问题是什么,现在试图解决它!

我有一个数据框,其中有一列填满了日期时间。这个数据框是一系列不同处理步骤的产物,这些步骤应用于一系列单独的文件,这些文件在某个时候合并为一个文件(这些个人由 id 列标识)。由于文件在某些​​时候必须以不同方式处理,因此日期时间列的格式在唯一 id 块之间不同 - 即一些单元格的格式为“%Y-%m-%d %H:%M:%S”和有些格式为“%d/%m/%Y %H:%M:%S”,尽管当我打开 csv 文件时它们看起来都是两种格式中的第二种。

我想加载数据并按唯一 ID 值拆分数据,然后根据日期时间列对其进行一系列其他操作。不幸的是,无论我尝试做什么,数据都不会被强制转换为单一类型的日期时间格式。我尝试重新格式化原始 csv 文件中的列,或者加载数据并将其重新分类为具有单一格式的 POSIXct 对象,但是当我这样做时,那些 id 块采用我没有使用 POSIXct 命令指定的格式 return 作为 NA(很明显!)。我还尝试将数据取消分类为数字格式。我尝试的任何方法似乎都不起作用,而且我的数据框太大,无法分别通过每个 id 块!必须有办法做到这一点,而且必须简单!请有人把我从痛苦中解救出来!非常感谢。

示例数据:

> dput(t)

  row_id            datetime id
1 165656 09/02/2017 15:50:55  1
2 165657 09/02/2017 15:51:25  1
3 165658 09/02/2017 15:51:55  1
4 165659 09/02/2017 15:52:25  1
5 165660 09/02/2017 15:52:55  1
6 165661 2017-02-09 15:53:25  2
7 165662 2017-02-09 15:53:55  2
8 165663 2017-02-09 15:54:25  2
9 165664 2017-02-09 15:54:55  2

我已经尝试了以下两种日期时间格式(这两种格式都只适用于其中一种):

>t$datetime = as.POSIXct(strptime(t$datetime, format="%Y-%m-%d %H:%M:%S"), tz="UTC")
>t$datetime
[1] NA                        NA                        NA                       
[4] NA                        NA                        "2017-02-09 15:53:25 UTC"
[7] "2017-02-09 15:53:55 UTC" "2017-02-09 15:54:25 UTC" "2017-02-09 15:54:55 UTC"

>t$datetime = unclass(as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S"))) 

您可以使用 ifelse 结合 grepl 在调用 as.POSIXct:

之前检查特定的日期格式掩码
t$dt <- ifelse(grepl("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}", t$datetime),
               as.POSIXct(strptime(t$datetime, "%d/%m/%Y %H:%M:%S")),
               as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S")))

这假设您只有两种日期格式。如果可能存在或更多,我们将不得不更改上述解决方案以将其考虑在内。

这里有一些示例数据可以证明这可以工作:

t <- data.frame(datetime=c("09/02/2017 15:50:55", "2017-02-09 15:50:55"))
t$dt <- ifelse(grepl("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}", t$datetime),
               as.POSIXct(strptime(t$datetime, "%d/%m/%Y %H:%M:%S")),
               as.POSIXct(strptime(t$datetime, "%Y-%m-%d %H:%M:%S")))
t

             datetime         dt
1 09/02/2017 15:50:55 1486651855   <-- same values for dt, as expected
2 2017-02-09 15:50:55 1486651855

我们可以使用 lubridate 中的 parse_date_time 并指定数据可以采用的各种格式。

library(lubridate)
df$datetime <- parse_date_time(df$datetime,c("%d/%m/%Y %T", "%Y-%m-%d %T"))
df$datetime

#[1] "2017-02-09 15:50:55 UTC" "2017-02-09 15:51:25 UTC" "2017-02-09 15:51:55 UTC"
#[4] "2017-02-09 15:52:25 UTC" "2017-02-09 15:52:55 UTC" "2017-02-09 15:53:25 UTC"
#[7] "2017-02-09 15:53:55 UTC" "2017-02-09 15:54:25 UTC" "2017-02-09 15:54:55 UTC"

class(df$datetime)
#[1] "POSIXct" "POSIXt" 

数据

df <- structure(list(row_id = structure(1:9, .Label = c("1 165656", 
"2 165657", "3 165658", "4 165659", "5 165660", "6 165661", "7 165662", 
"8 165663", "9 165664"), class = "factor"), datetime = structure(1:9,
.Label = c("09/02/2017 15:50:55", "09/02/2017 15:51:25", "09/02/2017 15:51:55", 
"09/02/2017 15:52:25", "09/02/2017 15:52:55", "2017-02-09 15:53:25", 
"2017-02-09 15:53:55", "2017-02-09 15:54:25", "2017-02-09 15:54:55"), 
class = "factor"), id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L)), 
class = "data.frame", row.names = c(NA, -9L))