0

我想将任何持续时间/周期字符串文字(以下面示例中显示的格式)解析为 Java 中的 Period/Duration 实例。

持续时间/期间是指包含基于日期和基于时间的数量的时间量。在 Java 中,Duration单独只适用于基于时间的量,如秒、分钟和小时,而Period单独只适用于基于日期的量,如年、月和日。

要解析的字符串并不总是包含所有数量。

例子:

  • 29 days 23 hours 59 minutes 20 seconds
  • 4 years 10 months 10 seconds
  • 10 days 9 minutes
  • 1 month

如果可能的话,我会怎么做?

4

1 回答 1

4

将您的字符串转换为 ISO 8601 格式并解析为 PeriodDuration

我的想法是使用PeriodDurationThreeTen Extra 项目的类。它结合了您已经提到的Period和类。Duration一个限制是它的parse方法只接受 ISO 8601 格式,所以我们需要先将你的字符串转换成那种格式。ISO 8601 格式就像P10DT9M10 天 9 分钟。P是固定的。T如果有一个(小时、分钟、秒)将它与基于日期的部分(年、月、周、天)分开,则标记基于时间的部分的开始。一个很好的结果是,我们总是可以分辨是M几个月还是分钟:如果M在之前T或没有T,它意味着几个月。如果M之后T, 表示分钟。我的第一个代码段将您的字符串转换为 ISO 8601。

    String[] examples = {
            "29 days 23 hours 59 minutes 20 seconds", 
            "4 years 10 months 10 seconds",
            "10 days 9 minutes", 
            "1 month" 
    };
    
    for (String pds : examples) {
        // If hours, minutes or seconds are present, put a T before them
        String temp = pds.replaceFirst("(\\d+ *(?:hour|minute|second))", " T $1");
        // Abbreviate all units to 1 letter; remove spaces
        temp = temp.replaceAll("([ymwdhms])[a-z]*", "$1").replace(" ", "");
        // Prepend P
        String iso = "P" + temp;
        System.out.println(iso);
    }

到目前为止的输出是:

P29dT23h59m20s
P4y10mT10s
P10dT9m
P1m

在此之后,我们应该能够解析:

        PeriodDuration pd = PeriodDuration.parse(iso);

我还没有安装 ThreeTen Extra,所以在发布之前我没有尝试过最后一行。OP 在评论中报告说,它就像 ThreeTen Extra 1.6.0 的魅力。唯一需要注意的是,解析字符串时单位必须按降序排列,否则会抛出DateTimeParseException.

不必担心 ISO 8601 格式通常以大写形式给出,而您的单位则以小写形式给出。该parse方法的文档指出:

这些部分的 ASCII 后缀为“Y”表示年,“M”表示月,“W”表示周,“D”表示天,“H”表示小时,“M”表示分钟,“S”表示秒,已接受大写或小写。

编辑:感谢 Arvind Kumar Avinash 的评论,如果您也需要接受大写字母,请在正则表达式中添加(?i)标志表达式以启用不区分大小写的匹配:

        temp = temp.replaceAll("(?i)([ymwdhms])[a-z]*", "$1").replace(" ", "");

链接

于 2021-07-03T12:45:54.493 回答