Java智能日期/时间解析器

10

有没有针对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"));

类似的问题:https://dev59.com/3G865IYBdhLWcg3wYNVS - Joel
这个 https://github.com/zoho/hawking 可以解决你的问题。 - Heisenberg
7个回答

12

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")

你的问题类似于这个


2
"自然语言日期解析" ≠ "格式猜测日期解析" - Matt Ball
不是,但在问题的背景下仍然有用。 - Joel

3

没有。如果输入的是“01/02/03”,应该返回的是:2003年1月1日,2001年2月3日或2001年3月2日?


如果将10/10/10视为任意组合的日/月/年,则其表示2010年10月10日,不考虑地区。那么对于08/09,解析器应该怎么做呢?在en-us中,它表示当前年份的9月8日,或者是2008年9月或2009年8月,还是会导致解析错误? - khachik
@khachik 哦,你说得对,我会把问题编辑为01/02/03。至于08/09 - 它应该返回3个选项中的一个,并以某种方式表明它不确定结果。理想情况下,它应该与人类行为类似... - fhucho
@fhucho 好的,继续吧。如果不确定结果应该如何表明,并且调用它的代码在这种情况下应该做什么? - khachik
@khachik 一个选项是 Parser p = new Parser(); p.parse("08/09"); p.getCertainity();。或者 parse(...) 可以返回一些包含 certainity 的对象。 - fhucho
在我的情况下,调用代码可能会显示类似于“获取上次更新时间错误”之类的内容,或者什么也不做,因为这种情况的概率几乎为零(在我的情况下)。 - fhucho
@fhucho 当调用代码得到一个代表发现一个或多个问题的“Certainity”对象时,它会做什么?你正在尝试证明可以制作这样的解析器。是的,这是可能的。这样的解析器对于特定情况可能有用,但不适用于一般情况。因此,如果JChronic或其他任何东西符合您的要求,您可以使用它。我已经在Python上制作了一个,但它非常具体,适合我的要求,并且我很久以前就遇到了同样的问题。 - khachik

2

你想称呼它为“智能”,但请考虑以下问题:

  • 你的1.2.2010和我的是否相同?
  • 如果代码在不同的时区和语言环境下运行会发生什么?
  • 它应该遵循一些已经确立的标准,还是完全发明自己的标准?

你的问题的答案是


1

这实际上是不可能的,或者至少不够可靠。

例如,字符串10/10/10 表示什么日期?


1
我不需要100%的可靠性。对于这种情况,解析函数可以有区域设置或语言作为可选参数。 - fhucho

1
如果你需要一个智能的日期/时间解析器,可以查看这个 https://github.com/zoho/hawking。Hawking 解析器是一个基于 Java 的 NLP 解析器,用于解析日期和时间信息。目前市面上最流行的像 Heidel Time、SuTime 和 Natty Date 时间解析器都是基于规则的,因此它们经常在解析需要考虑更复杂因素(如上下文、时态、多个值等)的日期/时间信息时遇到困难。
考虑到这一点,Hawking 解析器旨在解决许多这些挑战,并具有比其他可用的日期/时间解析器更多的优势。
它是一个开源库,使用 GPL v3 许可证,而且是最好的库。要了解为什么它是最好的,请查看这篇博客,其中详细说明了:https://www.zoho.com/blog/general/zias-nlp-based-hawking-date-time-parser-is-now-open-source.html 附注:我是这个项目的开发人员之一。

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

教程:日期时间了解更多关于现代日期时间 API 的内容。


0

你可以使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接