确定 Java 8 DateTimeFormatter 是否包含足够的时区信息

Determine if a Java 8 DateTimeFormatter includes enough timezone information

我有一些代码可以接收已解析的 DateTimeFormatter 实例。 现在在某些情况下,我看到那里没有 timezone/offset 信息,因此我 运行 进入解析错误(异常)。

为了避免这些错误,我想 'force' 一个默认的 timezone/offset 就像 ZoneOffset.UTC 一样,当没有指定任何内容时。

到目前为止,我还没有找到 'clean and documented' 的方法。

在这个例子中 getZone() 方法 returns null

ParseCaseSensitive(false)Value(DayOfMonth,2)'/'Text(MonthOfYear,SHORT)'/'Value(Year,4)' 'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Value(MilliOfSecond,3)' 'Offset(+HHMM,'+0000')

到目前为止,我想出的最好办法是执行 'toString()' 然后检查是否有所需的子字符串,如下所示:

String formatterExpression = formatter.toString();
if (formatterExpression.lastIndexOf("Offset(") == -1 &&
    formatterExpression.lastIndexOf("ZoneText(") == -1
    ) {
    formatter = formatter.withZone(defaultZone);
    LOG.error("The timestamp format \"{}\" does NOT contain a timezone so we assume \"{}\".",
        formatter.toString(), defaultZone.getDisplayName(TextStyle.SHORT, Locale.ENGLISH));
}

这样做的正确方法是什么?

其他背景信息 此代码是允许解析使用 strftime 格式指定格式的 date/time 文本的系统的一部分。

参见:

我明白你的意思,我也没有找到完美的解决方案,但我想我会分享几个选项。

如果格式化程序无法解析区域或偏移量,您可以设置像 UTC 这样的偏移量来使用,我建议:

formatter = new DateTimeFormatterBuilder().append(formatter)
        .parseDefaulting(ChronoField.OFFSET_SECONDS, ZoneOffset.UTC.getTotalSeconds())
        .toFormatter();

我还没有发现这会造成任何伤害的情况。如果格式化程序已经解析了区域或偏移量信息(或包含默认偏移量),则这将无效。如果没有,将使用指定的默认偏移量。

以上不适用于强制执行具有可变偏移量的时区(如夏令时 (DST) 的时区)。要执行一个,我相信你应该解析、获取并捕获异常,然后按照你已经找到的方式执行时区:

ZonedDateTime dateTime;
try {
    dateTime = ZonedDateTime.parse(dateTimeString, formatter);
} catch (DateTimeParseException dtpe) {
    dateTime = ZonedDateTime.parse(dateTimeString, 
                    formatter.withZone(ZoneId.of("Europe/Amsterdam")));
}

缺点是 catch 子句还会捕获与丢失偏移量或区域无关的错误。您可能会尝试解析异常消息,但我相信这只会给您留下一个类似于您开始时遇到的问题。我不会打扰。

恕我直言,我们真正缺少的是 getter 来获取格式化程序知道如何格式化和解析的字段。不过对于复杂的formatter来说,这种方法的设计和使用会比较有挑战性,所以我比较理解他们为什么不提供。