【问题标题】:Intelligent date / time parser for Java [closed]Java的智能日期/时间解析器[关闭]
【发布时间】:2011-05-12 02:23:02
【问题描述】:

是否有一些适用于 Java 的智能日期/时间解析器库?智能我的意思是,我不需要指定日期/时间格式。 API 应该与此类似:

Calendar cal = DateTimeParser.parse("01/06/10 14:55");
cal = DateTimeParser.parse("1 Jan 2009"); // assumes 00:00 time
cal = DateTimeParser.parse("1.2.2010");
cal = DateTimeParser.parse("kygyutrtf"); // throws exception

更新

// I'm telling the parser: "If unsure, assume US date format"
cal = DateTimeParser.parse("01/02/03", new Locale("en-us"));

【问题讨论】:

标签: java datetime


【解决方案1】:

java.time

您可以使用DateTimeFormatterBuilder 构建一个解析器,它可以处理不区分大小写的解析、可选模式(在方括号内指定)、默认缺少的字段(例如HOUR_OF_DAY)等。

演示:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        final DateTimeFormatter parser = new DateTimeFormatterBuilder()
                    .parseCaseInsensitive() // parse in case-insensitive manner                                     
                    .appendPattern("[M/d/uu[ H:m]][d MMM u][M.d.u][E MMM d, u]")
                    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                    .toFormatter(Locale.ENGLISH);
        
        // Test
        Stream.of(
                    "Thu Apr 1, 2021",
                    "THU Apr 1, 2021",
                    "01/06/10",
                    "1 Jan 2009",
                    "1.2.2010",
                    "asdf"
                ).forEach(s -> {
                    try {
                        System.out.println(LocalDateTime.parse(s, parser));
                    } catch(DateTimeParseException e) {
                        System.out.println("\"" + s + "\"" + " could not be parsed. Error: " + e.getMessage());
                    }
                });     
    }   
}

输出:

2021-04-01T00:00
2021-04-01T00:00
2010-01-06T00:00
2009-01-01T00:00
2010-01-02T00:00
"asdf" could not be parsed. Error: Text 'asdf' could not be parsed, unparsed text found at index 0

Trail: Date Time 了解有关现代日期时间 API 的更多信息。

【讨论】:

    【解决方案2】:

    如果您要求智能日期/时间解析器,请检查这个 https://github.com/zoho/hawking。由 ZOHO ZIA 团队下放。

    Hawking Parser 是一个基于 Java 的 NLP 解析器,用于解析日期和时间信息。最流行的解析器,如 Heidel Time、SuTime 和 Natty Date 时间解析器显然是基于规则的。因此,他们往往难以解析日期/时间信息,其中需要考虑更复杂的因素,如上下文、时态、多个值等。

    考虑到这一点,Hawking Parser 旨在解决许多此类挑战,并且与其他可用的日期/时间解析器相比具有许多明显的优势。

    它是 GPL v3 下的开源库,也是最好的库。要知道为什么它是最好的,请查看这个详细解释的博客:https://www.zoho.com/blog/general/zias-nlp-based-hawking-date-time-parser-is-now-open-source.html

    P.S:我是这个项目的开发者之一

    【讨论】:

      【解决方案3】:

      您可以使用org.pojava。这个库足够聪明,可以检测时间格式

      import org.pojava.datetime.DateTime;
      import java.util.Date;
      
      public class Main{
          public static void main(String[] args){
              String input1 = "6-Jan-69";
              String input2 = "10 Apr 85 12:34:15";
              String input3 = "7/Mar/77";
      
              Date date1 = DateTime.parse(input1).toDate();
              Date date2 = DateTime.parse(input2).toDate();
              Date date3 = DateTime.parse(input3).toDate();
      
              System.out.println(date1);
              System.out.println(date2);
              System.out.println(date3);
          }
      }
      

      输出

      Mon Jan 06 00:00:00 ICT 1969
      Wed Apr 10 12:34:15 ICT 1985
      Mon Mar 07 00:00:00 ICT 1977
      

      【讨论】:

        【解决方案4】:

        JodaTime 非常适合处理日期对象(例如 date.plusDays(10))

        ...但是 JChronic 是您想要的自然语言日期解析,例如

        Chronic.parse("now")
        Chronic.parse("tomorrow 15:00")
        Chronic.parse("14/2/2001")
        Chronic.parse("yesterday")
        Chronic.parse("20 Jan 2010")
        

        您的问题与this 类似。

        【讨论】:

        • "自然语言日期解析" != "格式猜测日期解析"
        • 否 - 但它在问题的上下文中仍然有用。
        【解决方案5】:

        好奇你想称它为智能,请考虑以下几点:

        • 你的1.2.2010和我的一样吗?
        • 如果代码在具有不同语言环境的不同时区运行会怎样?
        • 它应该遵循一些well established 标准还是完全自己发明?

        您的问题的答案是

        【讨论】:

          【解决方案6】:

          这不太可能,或者至少不够可靠。

          比如10/10/10这个字符串代表什么日期?

          【讨论】:

          • 我不需要 100% 的可靠性。对于这样的情况,parse 函数可能将语言环境或语言作为可选参数。
          【解决方案7】:

          不,没有。它应该在“01/02/03”返回什么? 2003 年 1 月 1 日、2001 年 2 月 3 日还是 2001 年 3 月 2 日?

          【讨论】:

          • @fhucho 10/10/10 是 2010 年 10 月 10 日,如果将其视为日/月/年的任何组合,则不考虑区域设置。解析器应该为08/09 做什么? en-us 是今年 9 月 8 日,还是 2008 年 9 月或 2009 年 8 月,否则会导致解析错误?
          • @khachik 哦,你是对的,我会将问题编辑到 01/02/03。至于 08/09 - 它应该返回 3 个选项之一,并以某种方式表明它不确定结果。理想情况下,它的行为应该与人类相似......
          • @fhucho 好的,让我们继续前进。它应该如何表明它不确定结果,以及在这种情况下调用它的代码应该做什么?
          • @khachik 一个选项是Parser p = new Parser(); p.parse("08/09"); p.getCertainity();。或者parse(...) 可以返回一些包含确定性的对象。
          • @khachik 在我的情况下,调用代码会显示类似“获取上次更新时间时出错”之类的内容,或者干脆什么都不做,因为这种情况的概率几乎为零(在我的情况下)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-11-09
          • 2010-11-27
          • 1970-01-01
          • 2010-09-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多