首页 > 解决方案 > 使用年份和不同的亚秒位数解析 LocalDateTime

问题描述

我有使用年和(1-365/366)加上日时间的数据,例如2018-338T14:02:57.47583,而不是年月日。

我正在尝试编写一个输入时间戳的函数,它通过一堆正则表达式运行它,并返回一个模式,我可以使用该模式通过 LocalDateTime.parse 解析该时间戳。我有一个功能可以做到这一点,除了一个问题。

public static String getInputFormat(String rawFirst) {
            
    String first = rawFirst.replaceAll("[^-.:/ a-zA-Z0-9]", "");
    
    ImmutableMap<String, String> regexFormatMap = new ImmutableMap.Builder<String, String>()
            .put("(-)?[0-9]{4}(Z?)", "YYYY")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(T)(([0-1][0-9])|(2[0-3])):[0-5][0-9](Z?)", "yyyy-DDD'T'HH:mm")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(T)(([0-1][0-9])|(2[0-3])):[0-5][0-9]:(([0-5][0-9])|60)(\\.([0-9]{1,6}))?(Z?)", "yyyy-DDD'T'HH:mm:ss.SSSSS")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(T)(([0-1][0-9])|(2[0-4]))(Z?)", "yyyy-DDD'T'HH")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(T)24((:00)|(:00:00))?(Z?)", "yyyy-DDD'T'HH:mm:ss")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(T)24:00:00(\\.([0]{1,6}))(Z?)", "yyyy-DDD'T'HH:mm:ss")
            .put("(-)?[0-9]{4}-((00[1-9])|(0[1-9][0-9])|([1-2][0-9][0-9])|(3(([0-5][0-9])|(6[0-6]))))(Z?)", "yyyy-DDD")
            .build();
            
    for (String regex : regexFormatMap.keySet()) {
        System.out.println(first.matches(regex) + ": " + first + " fits " + regex);
        if (first.matches(regex)) {
            System.out.println("Returning pattern " + regexFormatMap.get(regex));
            return regexFormatMap.get(regex);
        }
    }
            
    System.out.println("did not match pattern, returning default pattern used with test data, eventually this should just fail.");
    return "yyyy-DDD'T'HH:mm:ss.SSSSS";
}

我不知道如何处理任意数量的亚秒位数,即

等等

我想以尽可能普遍的方式做到这一点,所以理想情况下我不会检查每种可能性。

一种解决方案是让输出格式字符串有九个亚秒数字,然后填充输入字符串,但问题是检查是否应该填充它以及填充多少变得非常笨重。我希望它能够处理各种各样的字符串,并且只需通过向正则表达式映射添加更多条目而不是在其他地方添加复杂性和特殊情况来进行扩展。

也许我不能在这里得到我想要的一切,但如果你能想到一个解决方案,我会很乐意。谢谢!

标签: javaparsingtime

解决方案


您可以使用 anew DateTimeFormatterBuilder()来构建一个灵活的方法,使用该方法以秒的可变分数DateTimeFormatter解析s 。StringappendFraction(TemporalField, int, int, boolean)

例如像这样,我使用了 5 纳秒到 8 秒(这可能不是最好的主意,但它可以处理您String的所有示例):

DateTimeFormatter ldtVarFracSecFormatter =
        new DateTimeFormatterBuilder()
                .appendPattern("uuuu-DDD'T'HH:mm:ss")
                .appendFraction(ChronoField.NANO_OF_SECOND, 5, 8, true)
                .toFormatter(Locale.ENGLISH);

这是使用问题中的 s 的示例String

public static void main(String[] args) throws IOException {
    String a = "2018-338T14:02:57.47583";
    String b = "2018-338T14:02:57.475835"; 
    String c = "2018-338T14:02:57.4758352"; 
    String d = "2018-338T14:02:57.47583529";
    
    DateTimeFormatter ldtVarFracSecFormatter = 
            new DateTimeFormatterBuilder()
                    .appendPattern("uuuu-DDD'T'HH:mm:ss")
                    .appendFraction(ChronoField.NANO_OF_SECOND, 5, 8, true)
                    .toFormatter(Locale.ENGLISH);
    
    LocalDateTime aLdt = LocalDateTime.parse(a, ldtVarFracSecFormatter);
    LocalDateTime bLdt = LocalDateTime.parse(b, ldtVarFracSecFormatter);
    LocalDateTime cLdt = LocalDateTime.parse(c, ldtVarFracSecFormatter);
    LocalDateTime dLdt = LocalDateTime.parse(d, ldtVarFracSecFormatter);

    System.out.println(aLdt);
    System.out.println(bLdt);
    System.out.println(cLdt);           
    System.out.println(dLdt);
}

输出是(隐式使用LocalDateTime.toString()):

2018-12-04T14:02:57.475830
2018-12-04T14:02:57.475835
2018-12-04T14:02:57.475835200
2018-12-04T14:02:57.475835290

推荐阅读