有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将“20211120+01:00”格式的日期字符串解析为ZonedDateTime错误

如何将“2021-11-20+01:00”格式的日期解析为ZonedDateTime?我试着说:

String value = "2021-11-20+01:00";
ZonedDateTime zDate = ZonedDateTime.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-ddxxx"));

但是得到这个奇怪的错误:

java.time.format.DateTimeParseException: Text '2021-11-20+01:00' could not be parsed: Unable to obtain ZonedDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed

...Unsupported field: InstantSeconds...

有什么建议吗?European VIES VAT ID checking system在接收XML(SOAP)响应时使用此时间格式:<requestDate>2021-11-20+01:00</requestDate>。与OffsetDateTime相同的错误

有趣的是Javadoc说“三个字母(x)输出小时和分钟,带有冒号,比如“+01:30”。那么,为什么上述模式不起作用呢

也尝试了这一个-相同的错误:

ZonedDateTime zDate = ZonedDateTime.parse(value, DateTimeFormatter.ISO_OFFSET_DATE);

完整的错误日志:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-11-20 +01:00' could not be parsed: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
    at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:2017)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.OffsetDateTime.parse(OffsetDateTime.java:402)
    at javaapplication5.JavaApplication5.checkVATatVIES(JavaApplication5.java:162)
    at javaapplication5.JavaApplication5.main(JavaApplication5.java:65)
Caused by: java.time.DateTimeException: Unable to obtain OffsetDateTime from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:370)
    at java.base/java.time.format.Parsed.query(Parsed.java:235)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    ... 3 more
Caused by: java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {OffsetSeconds=3600},ISO resolved to 2021-11-20 of type java.time.format.Parsed
    at java.base/java.time.Instant.from(Instant.java:378)
    at java.base/java.time.OffsetDateTime.from(OffsetDateTime.java:365)
    ... 5 more
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
    at java.base/java.time.format.Parsed.getLong(Parsed.java:203)
    at java.base/java.time.Instant.from(Instant.java:373)
    ... 6 more

使用OpenJDK11


共 (3) 个答案

  1. # 1 楼答案

    tl;博士

    org.threeten.extra.OffsetDate.parse( "2021-11-20+01:00" )
    

    org.threeten.extra.OffsetDate

    java。Java中内置的time类不提供日期与偏移量组合的类。所以你的解析尝试毫无意义

    {a1}项目旨在补充java的功能。时间。它包括^{}类以满足您的特殊需要。将库添加到项目中

    String input = "2021-11-20+01:00" ;
    OffsetDate od = OffsetDate.parse( input ) ;
    

    从该OffsetDate对象可以获得LocalDate部分或ZoneOffset部分。您还可以确定其他日期时间值,例如添加一天中的某个时间以获得OffsetDateTime

    你评论道:

    if I make a request at 21th at 00:30 AM, I would get the response containing date of 20th.. because our time is UTC+2, and their time is UTC+1

    顺便提一下,我建议养成一个习惯,使用完整格式的小时偏移量,填充零,也填充分钟。虽然各种标准都允许,但我看到有多个库在缩写时失败。因此,我建议使用“+02:00”而不是“UTC+2”

    下面是一些示例代码,演示您描述的场景。我们使用Africa/Brazzaville的时区,因为它在那个时刻的偏移量为+01:00,我们使用Europe/Kaliningrad的偏移量为+02:00

    LocalDate ld = LocalDate.of( 2021 , Month.NOVEMBER , 21 );
    LocalTime lt = LocalTime.of( 0 , 30 );
    ZoneId zKaliningrad = ZoneId.of( "Europe/Kaliningrad" );
    ZonedDateTime zdtKaliningrad = ZonedDateTime.of( ld , lt , zKaliningrad );
    
    ZoneId zBrazzaville = ZoneId.of( "Africa/Brazzaville" );
    ZonedDateTime zdtBrazzaville = zdtKaliningrad.withZoneSameInstant( zBrazzaville );
    
    OffsetDate od = OffsetDate.from( zdtBrazzaville );
    
    OffsetDateTime odt = od.atTime( LocalTime.MIN );
    ZonedDateTime asSeenInKaliningrad = odt.atZoneSameInstant( zKaliningrad );
    

    跑步的时候

    zdtKaliningrad = 2021-11-21T00:30+02:00[Europe/Kaliningrad]
    zdtBrazzaville = 2021-11-20T23:30+01:00[Africa/Brazzaville]
    od = 2021-11-20+01:00
    odt = 2021-11-20T00:00+01:00
    asSeenInKaliningrad = 2021-11-20T01:00+02:00[Europe/Kaliningrad]
    

    就我个人而言,我质疑带偏移量的日期概念的实用价值,但这与你的问题无关

    在特定的时区工作通常比仅仅使用偏移量的问题要小

    我认为,更合理的做法是将区域作为一个时刻来跟踪日期,即一天开始的时间线上的点,以及指定的时区,而不是偏移量

    String result = 
        LocalDate
            .of( 2021 , 11 , 20 )
            .atStartOfDay( ZoneId.of( "Africa/Brazzaville" ) )
            .toString() 
    ;
    

    见此code run live at IdeOne.com

    2021-11-20T00:00+01:00[Africa/Brazzaville]

    对于表示一天的文本的数据交换,我建议以扩展ISO 8601的格式传输此字符串2021-11-20T00:00+01:00[Africa/Brazzaville],方法是在方括号中添加时区名称

  2. # 2 楼答案

    您可以自己将ur模式指定为如下字符串:

    String str = "2021-11-20+01:00";
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd+HH:mm");
    LocalDateTime date= LocalDateTime.parse(str, formatter);
    
  3. # 3 楼答案

    没有只包含日期和时区的Java类型。ZonedDateTime和OffsetDateTime,顾名思义,包含日期和时间。因此,您需要创建一个格式化程序,该格式化程序将假定一天中的默认时间:

    String value = "2021-11-20+01:00";
    
    DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
    builder.appendPattern("yyyy-MM-ddxxx");
    builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0);
    DateTimeFormatter formatter = builder.toFormatter();
    
    ZonedDateTime zDate = ZonedDateTime.parse(value, formatter);
    

    当然,一天中的小时可以是您选择的任何值:12例如,表示中午。但它必须是有效的