【问题标题】:Why R package lubridate can't parse vector with multiple formats?为什么 R 包 lubridate 无法解析多种格式的向量?
【发布时间】:2015-08-01 01:19:16
【问题描述】:

我正在使用包lubridate 来解析异类格式日期的向量并将它们转换为字符串,如下所示:

parse_date_time(c('12/17/1996 04:00:00 PM','4/18/1950 0130'), c('%m/%d/%Y %I:%M:%S %p','%m/%d/%Y %H%M'))

这是结果:

[1] NA NA
Warning message:
All formats failed to parse. No formats found.

如果我删除第一个格式字符串中的%p,它会错误地解析第一个日期字符串,并且仍然不解析第二个,如下所示:

[1] "1996-12-17 04:00:00 UTC" NA                       
Warning message:
 1 failed to parse. 

字符串中的 4PM 时间在结果中被解析为 4AM。

有没有人经历过这种奇怪的行为?

【问题讨论】:

  • 我能够复制错误。 parse_date_time(x = mydates, orders = c('m/d/Y I:M:S p','m/d/Y HM'), locale = "eng") 给出了第一个但不是第二个日期/时间的正确值。 parse_date_time(mydates1, orders = c('%m/%d/%Y %H%M')) 不起作用但是.... strptime(mydates1, format="%m/%d/%Y %H%M") 确实起作用了... 当mydates1 只是第二次约会时4/18/1950 0130
  • 我认为问题出在第二个字符串的 0130 上。如果你把它改成4/18/1950 01:30,我相信一切都会按预期进行。
  • @JasonAizkalns '0130' 可以单独解析:parse_date_time('0130', '%H%M') 给出"0-01-01 01:30:00 UTC"
  • @Pascal 很好,实际上,看起来4/18/1950 中的4 缺少前导零是问题所在。 parse_date_time("4/18/1950 0130", "%m%d%Y %H%M") 失败,但 parse_date_time("04/18/1950 0130", "%m%d%Y %H%M") 有效。
  • @Pascal 我已将 this issue 添加到 GitHub 存储库。

标签: r date lubridate


【解决方案1】:

这可能与您的系统区域设置有关。

  • parse_date_time {lubridate}

    p : 区域设置中的 AM/PM 指示符。与 I 结合使用,而不与 H 结合使用。在某些语言环境中为空字符串。

由于不同的语言有不同的 AM/PM 字符串,如果您的语言环境不是英语,即使您指定 lubridate 也不会选择 AM/PM 指示符。

操作系统中的区域设置可以包括显示语言、时间格式、时区。我正在使用美国时区和中国语言环境的英文窗口,所以我也一直在与 AM/PM 进行时间解析。

Sys.getlocale("LC_TIME")
[1] "Chinese (Simplified)_China.936"

您可以在 parse_date_time {lubridate} 中指定语言环境,但一开始对我不起作用:

Sys.setlocale("LC_TIME", "en_US") 
[1] ""
Warning message:
In Sys.setlocale("LC_TIME", "en_US") :
  OS reports request to set locale to "en_US" cannot be honored
  • locales {base}

    语言环境描述了程序国际化的各个方面。最初,R 语言环境的大多数方面都设置为“C”(这是 C 语言的默认设置,反映了北美的使用情况)。 strptime 用于 category = "LC_TIME"。

然后我找到了this用它成功了

Sys.setlocale("LC_TIME", "C")
[1] "C"

在此之后解析工作:

parse_date_time('12/17/1996 04:00:00 PM', '%m/%d/%Y %I:%M:%S %p')
[1] "1996-12-17 16:00:00 UTC"

您还可以指定时区和语言环境

parse_date_time('12/17/1996 04:00:00 PM', '%m/%d/%Y %I:%M:%S %p', tz = "America/New_York", locale = "C")
[1] "1996-12-17 16:00:00 EST"

【讨论】:

  • 你说得对,地区设置是上午/下午的问题。有一个专用的issue 为此开放。请注意,OP 的问题不仅仅在于 PM/AM。
【解决方案2】:

%p 部分的问题与语言环境有关。看到这个issue

无法解析与 lubridate guesser 的工作方式有关。

lubridate 有两种方式推断格式,灵活和精确。通过 flex 匹配,所有数字元素都可以具有灵活的长度(例如 404 都可以使用),但是元素之间必须有非数字分隔符。对于精确匹配器,不需要非数字分隔符,但元素必须具有精确的位数(如 04)。

很遗憾,您不能将两个匹配器组合在一个表达式中。修复这个问题并保持 lubridate 解析器当前的灵活性将非常困难。

在你的例子中

> parse_date_time('4/18/1950 0130', 'mdY HM')
[1] NA
Warning message:
All formats failed to parse. No formats found. 

您想在日期部分4/18/1950 上执行弹性匹配并在时间部分0130 上执行精确匹配。

请注意,如果您的日期时间完全采用 flex 或完全采用 exact 格式,则解析将按预期工作:

> parse_date_time('04/18/1950 0130', 'mdY HM')
[1] "1950-04-18 01:30:00 UTC"
> parse_date_time('4/18/1950 1:30', 'mdY HM')
[1] "1950-04-18 01:30:00 UTC"

lubridate 1.4.1 通过向parse_date_timeexact=FALSE 添加新参数来“修复”此问题。当设置为TRUE 时,orders 参数被解释为包含精确的strptime 格式并且不执行猜测或训练。通过这种方式,您可以根据需要添加任意数量的精确格式,而且您还可以提高速度,因为根本不需要进行猜测。

> parse_date_time(c('12/17/1996 04:00:00','4/18/1950 0130'),
+                 c('%m/%d/%Y %I:%M:%S','%m/%d/%Y %H%M'),
+                 exact = T)
[1] "1996-12-17 04:00:00 UTC" "1950-04-18 01:30:00 UTC"

与此相关,有一个明确的requested 要求提供这样的选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-20
    • 2018-05-31
    • 1970-01-01
    • 2020-07-04
    • 2016-05-24
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多