用 Joda Time 解析冗余信息

Parsing redundant information with Joda Time

我正在处理如下字符串:0022 GMT (0822 HKT) July 21, 2016

显然,这些字符串为两个不同的时区指定了两次一天中的时间。 Joda Time 的DateTimeFormat.forPattern() 的模式语法可以处理这种冗余信息吗?

一种可能性是忽略两个时间表达式 0022 GMT0822 HKT 中的一个。这将需要某种通配符,它​​可以匹配要忽略的时间表达式的一部分,看起来像 Hm z '(*)' MMM dd, y.

Joda Time 的模式语法中是否存在这样的通配符或其他任何可以解析上述时间字符串的内容?

为了忽略潜在的矛盾部分(在其他区域重复小时、分钟和区域名称),您必须在 Joda-Time[=27= 中编写自己的 DateTimeParser ]:

DateTimeFormatter dtf =
    new DateTimeFormatterBuilder().appendPattern("HHmm 'GMT' (").append(
        new DateTimeParser() {
            @Override
            public int estimateParsedLength() {
                return 10;
            }
            @Override
            public int parseInto(DateTimeParserBucket bucket, String text, int position) {
                int pos = position;
                while (text.charAt(pos) != ')') {
                    pos++;
                }
                return pos;
            }
        }
    )
    .appendPattern(") MMMM dd, yyyy")
    .toFormatter()
    .withLocale(Locale.US)
    .withZoneUTC();

String input = "0022 GMT (0822 HKT) July 21, 2016";    
DateTime dt = dtf.parseDateTime(input);
System.out.println("Joda: " + dt); // 2016-07-21T00:22:00.000Z

供您参考,我在 Java-8 中看不到任何方法(没有输入预处理),请参阅此示例,它将抛出一个即使使用可选部分也是例外。 Java-8 缺少编写自己的解析器的机制。

DateTimeFormatter dtf = 
  DateTimeFormatter.ofPattern("HHmm z ([HHmm z]) MMMM dd, uuuu", Locale.US);
ZonedDateTime zdt = ZonedDateTime.parse(input, dtf); // throws exception!!!
// java.time.format.DateTimeParseException: 
// Text '0022 GMT (0822 HKT) July 21, 2016' could not be parsed at index 10

旁注:当您探索我的库 Time4J 时,它提供了适用于 Java-8 的替代且性能更高的解析引擎,然后它提供了一个更简单的解决方案比 Joda-Time,看这个小 gist example.

否则,始终可以使用字符串预处理编写 hackish 解决方法(在不允许使用第 3 方库时很有趣):

String input = "0022 GMT (0822 HKT) July 21, 2016";
StringBuilder sb = new StringBuilder();
boolean markedForRemoval = false;
for (int i = 0; i < input.length(); i++) {
    char c = input.charAt(i);
    if (c == ')') {
        markedForRemoval = false;
    }
    if (!markedForRemoval) {
        sb.append(c);
    }
    if (c == '(') {
        markedForRemoval = true;
    }
}
input = sb.toString();
System.out.println(input); // 0022 GMT () July 21, 2016
// continue parsing the changed input based on a formatter of your choice