如何使用默认区域解析ZonedDateTime? [英] How to parse ZonedDateTime with default zone?

查看:755
本文介绍了如何使用默认区域解析ZonedDateTime?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从不包含 zone 和其他字段的字符串中解析 ZoneDateTime $ / b
$ b

这里是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 {
defDateTimeFormatter.ISO_ZONED_DATE_TIME parsing incomplete date:#value #expected(){
expect:
ZonedDateTime.parse(value,DateTimeFormatter.ISO_ZONED_DATE_TIME)== expected
其中:
value |预计
'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())
}
}

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




  • '2014-04 -23T04:30:45.123'无法在索引23中解析

  • '2014-04-23T04:30'无法在索引16中解析

  • '2014-04-23'无法在索引10中解析



如何解析设置的时间和区域的不完整日期由于 ISO_ZONED_DATE_TIME 格式化程序期望区域或偏移量信息,因此,

解决方案

解析失败。
您必须为Zone信息和时间部分提供具有可选部分的 DateTimeFormatter
逆向工程不是很难逆向工程化ZonedDateTimeFormatter 并添加可选标记。



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

  DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.optionalStart()// time made optional
.appendLiteral('T ')
.append(ISO_LOCAL_TIME)
.optionalStart()//区域和偏移量为可选
.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());


How to parse ZoneDateTime from string that doesn't contain zone and others fields?

Here is test in Spock to reproduce:

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:

  • '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

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

解决方案

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

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

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());

这篇关于如何使用默认区域解析ZonedDateTime?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆