Java 如何使用默认区域解析 ZonedDateTime?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27293994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 04:07:15  来源:igfitidea点击:

How to parse ZonedDateTime with default zone?

javadatejava-8java-time

提问by Sergey Ponomarev

How to parse ZoneDateTimefrom string that doesn't contain zoneand others fields?

如何ZoneDateTime从不包含zone其他字段的字符串中解析?

Here is test in Spock to reproduce:

这是在 Spock 中重现的测试:

import spock.lang.Specification
import spock.lang.Unroll

import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter

@Unroll
class ZonedDateTimeParsingSpec extends Specification {
    def "DateTimeFormatter.ISO_ZONED_DATE_TIME parsing incomplete date: #value #expected"() {
        expect:
        ZonedDateTime.parse(value, DateTimeFormatter.ISO_ZONED_DATE_TIME) == expected
        where:
        value                           | expected
        '2014-04-23T04:30:45.123Z'      | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.UTC)
        '2014-04-23T04:30:45.123+01:00' | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.ofHours(1))
        '2014-04-23T04:30:45.123'       | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneId.systemDefault())
        '2014-04-23T04:30'              | ZonedDateTime.of(2014, 4, 23, 4, 30, 0, 0, ZoneId.systemDefault())
        '2014-04-23'                    | ZonedDateTime.of(2014, 4, 23, 0, 0, 0, 0, ZoneId.systemDefault())
    }
}

First two test passed, all others failed with DateTimeParseException:

前两个测试通过了,所有其他测试都失败了 DateTimeParseException:

  • '2014-04-23T04:30:45.123' could not be parsed at index 23
  • '2014-04-23T04:30' could not be parsed at index 16
  • '2014-04-23' could not be parsed at index 10
  • 无法在索引 23 处解析“2014-04-23T04:30:45.123”
  • 无法在索引 16 处解析“2014-04-23T04:30”
  • 无法在索引 10 处解析“2014-04-23”

How can I parse incomplete dates with time and zone setted to default?

如何在时间和区域设置为默认值的情况下解析不完整的日期?

采纳答案by bowmore

Since the ISO_ZONED_DATE_TIMEformatter expects zone or offset information, parsing fails. You'll have to make a DateTimeFormatterthat has optional parts for both the zone information and the time part. It's not too hard reverse engineering the ZonedDateTimeFormatterand adding optional tags.

由于ISO_ZONED_DATE_TIME格式化程序需要区域或偏移信息,因此解析失败。您必须制作一个DateTimeFormatter具有区域信息和时间部分的可选部分。逆向工程ZonedDateTimeFormatter和添加可选标签并不太难。

Then you parse the Stringusing the parseBest()method of the formatter. Then, for suboptimal parse results you can create the ZonedDateTimeusing any default you want.

然后你String使用parseBest()格式化程序的方法解析。然后,对于次优的解析结果,您可以ZonedDateTime使用任何您想要的默认值来创建。

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .append(ISO_LOCAL_DATE)
        .optionalStart()           // time made optional
        .appendLiteral('T')
        .append(ISO_LOCAL_TIME)
        .optionalStart()           // zone and offset made optional
        .appendOffsetId()
        .optionalStart()
        .appendLiteral('[')
        .parseCaseSensitive()
        .appendZoneRegionId()
        .appendLiteral(']')
        .optionalEnd()
        .optionalEnd()
        .optionalEnd()
        .toFormatter();

TemporalAccessor temporalAccessor = formatter.parseBest(value, ZonedDateTime::from, LocalDateTime::from, LocalDate::from);
if (temporalAccessor instanceof ZonedDateTime) {
    return ((ZonedDateTime) temporalAccessor);
}
if (temporalAccessor instanceof LocalDateTime) {
    return ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault());
}
return ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault());

回答by JodaStephen

The formatter has a withZone()methodthat can be called to provide the missing time-zone.

格式化程序有一个withZone()方法可以调用以提供缺少的时区。

ZonedDateTime.parse(
    value,
    DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneId.systemDefault()))

Bear in mind that there was a bug, so you need 8u20 or later for it to work fully.

请记住,存在一个错误,因此您需要 8u20 或更高版本才能使其完全工作。