【问题标题】:Determine if a Java 8 DateTimeFormatter includes enough timezone information确定 Java 8 DateTimeFormatter 是否包含足够的时区信息
【发布时间】:2018-06-17 11:50:16
【问题描述】:

我有一些代码接收解析的DateTimeFormatter 实例。 现在在某些情况下,我发现那里没有时区/偏移信息,因此我遇到了解析错误(异常)。

为了避免这些错误,我想在未指定任何内容时“强制”使用默认时区/偏移量,例如 ZoneOffset.UTC

到目前为止,我还没有找到一种“干净且有文档记录”的方法来执行此操作。

在此示例中,getZone() 方法返回 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 格式指定格式的日期/时间文本。

见:

【问题讨论】:

  • 你的意思是你收到了一个由DateTimeFormatter.ofPattern 方法之一生成的DateTimeFormatter 对象(在它解析了格式模式字符串之后)?或者您的意思是您收到来自DateTimeFormatter.parse 方法之一的TemporalAccessor?抱歉,不是很清楚。
  • 恕我直言,您“序列化”格式化程序的想法不是一个好主意。不让DateTimeFormatter 可序列化是一个明智的设计决定。与其像格式化程序那样“格式化”和“重新解析”固有的复杂对象,不如只发送格式化模式字符串以及区域 ID 和区域设置,这样接收者就可以轻松地重建原始格式化程序。

标签: java datetime java-8 timezone timezone-offset


【解决方案1】:

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

如果格式化程序无法解析区域或偏移量时,如果您可以设置使用 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。不过,对于复杂的格式化程序,这种方法的设计和使用会很有挑战性,所以我倾向于理解他们为什么不提供这种方法。

【讨论】:

  • 拥有像 UTC 这样的简单“固定”偏移量很好,所以我非常喜欢 parseDefaulting 构造。是否有可能检测到它将被/被使用,以便我可以发出警告消息?
  • 不是真的(据我所知)。 hack 可能会默认为一个奇数的偏移量,否则永远不会使用,例如 7 秒或 60013 秒,然后在解析后您可以检测是否使用了此偏移量(如果您愿意,可以更改为 UTC)。
猜你喜欢
  • 1970-01-01
  • 2017-09-21
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
相关资源
最近更新 更多