【问题标题】:Parsing dates with different formats解析不同格式的日期
【发布时间】:2018-03-20 17:33:14
【问题描述】:

我有一个 csv 文件,其中有一列包含日期,但日期有两种不同的格式:“m/d/y H:M”和“y m d H:M:S”。我想用一种格式创建一个包含这些日期的新专栏(我不在乎哪一种)。我尝试了 parse_date_time 函数,但它只适用于其中一种格式,而不适用于两种格式。我该怎么做?

这是我尝试使用的代码:

newdata <- mutate(data,
                        newcolumn = parse_date_time(x = data$date_column,
                                                        orders = c("m/d/y H:M", "y m d H:M:S"),
                                                        locale = "eng") )

以下是列中的一些示例日期:

x <- c("6/21/2006 0:00",
       "1889-06-13 00:00:00",
       "6/28/2012 0:00",
       "5/19/2015 0:00",
       "6/6/2016 0:00",
       "1884-05-24 00:00:00",
       "7/28/2013 0:00")

【问题讨论】:

  • 可以发一下专栏吗?这将使回答更容易,并确保答案对您有效
  • @DanHall 我刚刚从专栏中添加了一些示例日期,这是一个非常大的数据集,所以我不能全部发布
  • 为了将来参考,请使用dput(x),其中x 是您的对象的一小部分,它重现了问题并具有您的对象的所有特征。复制并粘贴 dput 的输出作为您问题的一部分。但我想我已经在下面为你提供了一个应该可行的答案。
  • 好的,现在可以了。这比我想象的要棘手:)

标签: r date parsing


【解决方案1】:

使用lubridate::parse_date_time()

library(lubridate)
library(dplyr)

x <- c("6/21/2006 0:00",
       "1889-06-13 00:00:00",
       "6/28/2012 0:00",
       "5/19/2015 0:00",
       "6/6/2016 0:00",
       "1884-05-24 00:00:00",
       "7/28/2013 0:00")

df <- data_frame(date_column = x)
df_new <- df %>% 
  mutate(new_column = parse_date_time(date_column, orders = c('ymdHMS', "mdyHM")))

df_new
# A tibble: 7 x 2
  date_column         new_column         
  <chr>               <dttm>             
1 6/21/2006 0:00      2006-06-21 00:00:00
2 1889-06-13 00:00:00 1889-06-13 00:00:00
3 6/28/2012 0:00      2012-06-28 00:00:00
4 5/19/2015 0:00      2015-05-19 00:00:00
5 6/6/2016 0:00       2016-06-06 00:00:00
6 1884-05-24 00:00:00 1884-05-24 00:00:00
7 7/28/2013 0:00      2013-07-28 00:00:00

【讨论】:

    【解决方案2】:

    anytime 包就是这样做的——启发式地评估合理的格式:

    R> library(anytime)
    R> x <- c("6/21/2006 0:00",
    +        "1889-06-13 00:00:00",
    +        "6/28/2012 0:00",
    +        "5/19/2015 0:00",
    +        "6/6/2016 0:00",
    +        "1884-05-24 00:00:00",
    +        "7/28/2013 0:00")
    R> anytime(x)
    [1] "2006-06-21 CDT" "1889-06-13 CST" "2012-06-28 CDT"
    [4] "2015-05-19 CDT" NA               "1884-05-24 CST"
    [7] "2013-07-28 CDT"
    R> 
    

    默认情况下,它使用 Boost 的 date_time 库解析器,并且 做个位数的月/日,因此元素 6 上的 NA。但我们还添加了 R 的解析器作为后备:

    R> anytime(x, useR=TRUE)
    [1] "2006-06-21 CDT" "1889-06-13 CST" "2012-06-28 CDT"
    [4] "2015-05-19 CDT" "2016-06-06 CDT" "1884-05-24 CST"
    [7] "2013-07-28 CDT"
    R> 
    

    所以这里一切正常没有单一的格式规范。

    【讨论】:

      【解决方案3】:

      所以我们首先将两者分开:

      x <- c("03/20/2018 10:42", "2018-03-20 10:37:02")
      DF <- data.frame(x = x, stringsAsFactors = FALSE)
      slash_index <- grep("/", DF$x)
      slash <- DF$x[slash_index]
      dash <- DF$x[-slash_index]
      

      然后我们转换它们。我喜欢 lubridate,但如果你愿意,可以使用你的方法

      library(lubridate)
      slash <- mdy_hm(slash)
      dash <- ymd_hms(dash)
      

      然后我们将它们放入一个日期向量中:

      date_times <- integer(0)
      date_times[slash_index] <- slash
      date_times[seq_along(DF$x)[-slash_index]] <- dash
      DF$x <- as.POSIXct(date_times, origin = "1970-01-01 00:00:00")
      DF
      #                     x
      # 1 2018-03-20 03:42:02
      # 2 2018-03-20 03:37:02
      

      注意:
      这里棘手的部分是根据向量的索引将向量的一部分重新分配给向量。当向量的一部分分配给POSIXct 对象时,它的属性被剥离,将其转换为日期时间的内部整数代码。通过在开始时剥离属性,然后在结束时重新分配类来解决此问题。

      这是您的示例的完整内容:

      install.packages("lubridate")
      library(lubridate)
      x <- c("6/21/2006 0:00",
             "1889-06-13 00:00:00",
             "6/28/2012 0:00",
             "5/19/2015 0:00",
             "6/6/2016 0:00",
             "1884-05-24 00:00:00",
             "7/28/2013 0:00")
      DF <- data.frame(x = x, stringsAsFactors = FALSE)
      slash_index <- grep("/", DF$x)
      slash <- DF$x[slash_index]
      dash <- DF$x[-slash_index]
      
      
      slash <- mdy_hm(slash)
      dash <- ymd_hms(dash)
      
      
      date_times <- integer(0)
      date_times[slash_index] <- slash
      date_times[seq_along(DF$x)[-slash_index]] <- dash
      DF$x <- as.POSIXct(date_times, origin = "1970-01-01 00:00:00", tz = "UTC")
      DF
      #            x
      # 1 2006-06-21
      # 2 1889-06-13
      # 3 2012-06-28
      # 4 2015-05-19
      # 5 2016-06-06
      # 6 1884-05-24
      # 7 2013-07-28
      

      因为这些时间都是"00:00:00",所以它们被截断了。您可以使用this question 的答案中描述的方法将它们与"00:00:00" 一起显示。

      【讨论】:

        猜你喜欢
        • 2022-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-28
        • 2011-03-10
        • 2019-04-27
        相关资源
        最近更新 更多