【问题标题】:Parse dates in format dmy together with dmY using parse_date_time使用 parse_date_time 将 dmy 格式的日期与 dmY 一起解析
【发布时间】:2013-10-01 22:30:22
【问题描述】:

我有一个日期字符表示向量,其中格式主要是 dmY(例如 27-09-2013)、dmy(例如 27-09-13),偶尔还有一些 b 或 @987654327 @月。因此,parse_date_timelubridate 中的“允许用户指定几种格式顺序来处理异构日期时间字符表示”对我来说可能是一个非常有用的功能。

但是,parse_date_time 似乎在解析 dmy 日期与 dmY 日期一起出现时出现问题。单独解析 dmydmy 以及与我相关的其他一些格式时,它工作正常。在对@Peyton 的回答here 的评论中也注意到了这种模式。有人建议快速修复,但我想问一下是否可以在lubridate 中处理它。

这里我展示了一些示例,其中我尝试解析 dmy 格式的日期以及其他一些格式,并相应地指定 orders

library(lubridate)
# version: lubridate_1.3.0

# regarding how date format is specified in 'orders':
# examples in ?parse_date_time
# parse_date_time(x, "ymd")
# parse_date_time(x, "%y%m%d")
# parse_date_time(x, "%y %m %d")
# these order strings are equivalent and parses the same way
# "Formatting orders might include arbitrary separators. These are discarded"

# dmy date only
parse_date_time(x = "27-09-13", orders = "d m y")
# [1] "2013-09-27 UTC"
# OK

# dmy & dBY
parse_date_time(c("27-09-13", "27 September 2013"), orders = c("d m y", "d B Y"))
# [1] "2013-09-27 UTC" "2013-09-27 UTC"
# OK

# dmy & dbY
parse_date_time(c("27-09-13", "27 Sep 2013"), orders = c("d m y", "d b Y"))
# [1] "2013-09-27 UTC" "2013-09-27 UTC"
# OK

# dmy & dmY
parse_date_time(c("27-09-13", "27-09-2013"), orders = c("d m y", "d m Y"))
# [1] "0013-09-27 UTC" "2013-09-27 UTC"
# not OK

# does order of the date components matter?
parse_date_time(c("2013-09-27", "13-09-13"), orders = c("Y m d", "y m d"))
# [1] "2013-09-27 UTC" "0013-09-27 UTC"
# no

select_formats 参数呢?很抱歉这么说,但我很难理解帮助文件的这一部分。还有一个search for select_formats on SO: 0 个结果。不过,这部分似乎是相关的:“默认情况下,选择具有最多格式化令牌 (%) 的格式,并且 %Y 计为 2.5 个令牌(因此它可以优先于 %y%m)。”。所以我(拼命地)尝试了一些额外的dmy日期:

parse_date_time(c("27-09-2013", rep("27-09-13", 10)), orders = c("d m y", "d m Y"))
# not OK. Tried also 100 dmy dates.

# does order in the vector matter?
parse_date_time(c(rep("27-09-13", 10), "27-09-2013"), orders = c("d m y", "d m Y"))
# no

然后我检查了guess_formats 函数(也在lubridate 中)如何处理dmydmY

guess_formats(c("27-09-13", "27-09-2013"), c("dmy", "dmY"), print_matches = TRUE)
#                   dmy        dmY       
# [1,] "27-09-13"   "%d-%m-%y" ""        
# [2,] "27-09-2013" "%d-%m-%Y" "%d-%m-%Y"
# OK   

来自?guess_formatsy also matches Y。来自?parse_date_timey* Year without century (00–99 or 0–99). Also matches year with century (Y format)。所以我尝试了:

guess_formats(c("27-09-13", "27-09-2013"), c("dmy"), print_matches = TRUE)
#                   dmy       
# [1,] "27-09-13"   "%d-%m-%y"
# [2,] "27-09-2013" "%d-%m-%Y"
# OK

因此,guess_format 似乎能够与dmY 一起处理dmy。但是我怎么能告诉parse_date_time 做同样的事情呢?提前感谢任何 cmets 或帮助。

更新 我在lubridate bug report 上发布了这个问题,并得到了@vitoshka 的快速回复:“这是一个错误”。

【问题讨论】:

    标签: r date lubridate


    【解决方案1】:

    它看起来像一个错误。我不确定所以你应该联系维护者。

    构建包源并在此内部函数中更改一行(我将which.max替换为wich.min):

    .select_formats <-   function(trained){
      n_fmts <- nchar(gsub("[^%]", "", names(trained))) + grepl("%Y", names(trained))*1.5
      names(trained[ which.min(n_fmts) ]) ## replace which.max  by which.min
    }
    

    似乎解决了这个问题。坦率地说,我不知道为什么会这样,但我想这是一种排名..

    parse_date_time(c("27-09-13", "27-09-2013"), orders = c("d m y", "d m Y"))
    [1] "2013-09-27 UTC" "2013-09-27 UTC"
    
    parse_date_time(c("2013-09-27", "13-09-13"), orders = c("Y m d", "y m d"))
    [1] "2013-09-27 UTC" "2013-09-13 UTC"
    

    【讨论】:

    • parse_date_time 函数似乎发生了一些可疑的事情。对于初学者,select_formats= 参数永远不会被使用,而不是 .select_formats 内部函数。 .select_formats 也不像它所说的那样关注各种格式的出现频率。 %d-%m-%Y 将永远胜过 %d-%m-%y,因为它通过上面的 grepl 调用获得了额外的 1.5 权重。例如:1e5:1 的比例没有区别lubridate:::.select_formats(structure(c(100000,1), .Names = c("%d-%m-%y", "%d-%m-%Y")))
    • 接下来,如果你取最小值而不是最大值,你就会颠倒排名并让%d-%m-%y获胜,这会以某种方式让事情正常进行。
    • @thelatemail 好猜!另外,函数是递归的(我不知道为什么?)所以很难调试!
    • @agstudy,非常感谢您的回答和建议的解决方案 (+1)。我将在github of lubridate 上发布此问题的链接。
    • @thelatemail,感谢您在 select_formats 上提供的非常有帮助的 cmets。
    【解决方案2】:

    这实际上是故意的。我现在想起来了。假设如果您在同一个向量中有 01-02-1845 和 01-02-03 形式的日期,那么它可能是 01-02-0003 的意思。它还避免与不同世纪的日期混淆。你无法知道17-05-13 是指 20 世纪还是 21 世纪。

    这个决定可能还有技术原因,但我现在不记得了。

    .select_formats 参数是要走的路:

    my_select <-   function(trained){
      n_fmts <- nchar(gsub("[^%]", "", names(trained))) +
        grepl("%y", names(trained))*1.5
      names(trained[ which.max(n_fmts) ])
    }
    
    parse_date_time(c("27-09-13", "27-09-2013"), "dmy", select_formats = my_select)
    ## [1] "2013-09-27 UTC" "2013-09-27 UTC"
    

    select_formats 应该返回要按顺序应用于输入字符向量的格式。在上面的示例中,您优先考虑 %y 格式。

    我正在将此示例添加到文档中。

    【讨论】:

    • 非常感谢您澄清这个“问题”。我尝试了您建议的代码,但没有得到相同的结果...[1] "0013-09-27 UTC" "2013-09-27 UTC"。奇怪的。此外,我发现您的“故意”论点与parse_date_time(c("27-09-13", "27 Sep 2013"), orders = c("d m y", "d b Y")) 的输出不一致。在这种情况下,是什么让“13”更像“2013”​​?
    • @Henrik,你应该使用最新的 github。如其他 cmets 所述,以前未使用 select_format 参数。您对一致性原因是正确的。这是不一致的,这确实很糟糕。顺便说一句,orders=c("d m y", "d b Y",就相当于orders="dmy"。 y order 代表 %y 和 %Y 格式。这是记录在案的。
    • 感谢您指向 github。我了解 %y 与 %Y (请参阅我的 OP)。在这里,我使用了“b”来处理“Sep”。从?parse_date_time 来看,select_formats 参数没有被使用并不完全清楚。
    • “你无法知道 17-05-13 是指 20 世纪还是 21 世纪。”。显然parse_date_time 'knows' 13 是 2013 年 17-05-13 与 dbY 或 dBy 一起。这是我的问题的要点之一。
    • @Henrik,未使用 select_format,这是一个错误。一两周前在github上修复了。
    猜你喜欢
    • 1970-01-01
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    相关资源
    最近更新 更多