使用 ZonedDateTime 解析日期时出现 DateTimeParseException

发布于 2025-01-14 02:28:59 字数 901 浏览 1 评论 0原文

我有下面的程序,看起来 ZonedDateTime 无法解析日期字符串。我应该使用不同的日期格式或不同的库来解析吗?

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

class Scratch {
    public static void main(String[] args) {
        final String inputDate = "2022-03-12T03:59:59+0000Z";
        ZonedDateTime.parse(inputDate, DateTimeFormatter.ISO_DATE_TIME).toEpochSecond();
    }
}

Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-03-12T03:59:59+0000Z' could not be parsed, unparsed text found at index 19
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:599)
    at Scratch.main(scratch_29.java:7)

Process finished with exit code 1

I have the below program and looks like ZonedDateTime is not able to parse the date string. Should I use a different date format or different library to parse?

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

class Scratch {
    public static void main(String[] args) {
        final String inputDate = "2022-03-12T03:59:59+0000Z";
        ZonedDateTime.parse(inputDate, DateTimeFormatter.ISO_DATE_TIME).toEpochSecond();
    }
}

Exception in thread "main" java.time.format.DateTimeParseException: Text '2022-03-12T03:59:59+0000Z' could not be parsed, unparsed text found at index 19
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2053)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1952)
    at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:599)
    at Scratch.main(scratch_29.java:7)

Process finished with exit code 1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

兮颜 2025-01-21 02:28:59

这不是 ISO_DATE_TIME 格式。这需要类似 2022-03-12T03:59:59+0000 (没有“Z”)。一个有效的格式化程序看起来像:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;


class Scratch {
    public static void main(String[] args) {
        final String inputDate = "2022-03-12T03:59:59+0000Z";

        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                .optionalStart()
                .appendPattern(".SSS")
                .optionalEnd()
                .optionalStart()
                .appendZoneOrOffsetId()
                .optionalEnd()
                .optionalStart()
                .appendOffset("+HHMM", "0000")
                .optionalEnd()
                .optionalStart()
                .appendLiteral('Z')
                .optionalEnd()
                .toFormatter();

        long epochSecond = ZonedDateTime.parse(inputDate, formatter).toEpochSecond();

        System.out.println("epochSecond is " + epochSecond);
    }
}

源自这篇文章。您可以在一处创建该格式化程序并再次使用它。

That isn't a ISO_DATE_TIME format. That would require something like 2022-03-12T03:59:59+0000 (no 'Z'). A formatter that works looks something like:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;


class Scratch {
    public static void main(String[] args) {
        final String inputDate = "2022-03-12T03:59:59+0000Z";

        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                .optionalStart()
                .appendPattern(".SSS")
                .optionalEnd()
                .optionalStart()
                .appendZoneOrOffsetId()
                .optionalEnd()
                .optionalStart()
                .appendOffset("+HHMM", "0000")
                .optionalEnd()
                .optionalStart()
                .appendLiteral('Z')
                .optionalEnd()
                .toFormatter();

        long epochSecond = ZonedDateTime.parse(inputDate, formatter).toEpochSecond();

        System.out.println("epochSecond is " + epochSecond);
    }
}

as derived from this post. You can create that formatter in one place and use it over again.

江南烟雨〆相思醉 2025-01-21 02:28:59

tl;dr

您的输入恰好是 java.time.Instant 类默认使用的标准 IS0 8601 格式的扭曲变体。修复您的输入字符串并解析。

Instant.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) )

或者,重新格式化:

Instant.parse
( 
    "2022-03-12T03:59:59+0000Z"
    .replace( "+0000Z" , "Z" ) 
)

查看此代码在 IdeOne.com 上实时运行。

2022-03-12T03:59:59Z

但最好的解决方案是在交换日期时间值时仅使用 ISO 8601 格式。

详细信息

ZonedDateTime 此处不合适

ZonedDateTime 是您输入的错误类。您的输入有一个 Z,它是与 UTC 零小时-分钟-秒的偏移量的标准缩写。但没有指示时区,仅显示偏移量。因此,请使用 OffsetDateTimeInstant 而不是 ZonedDateTime

+0000Z 冗余

+0000 还意味着零时-分-秒的偏移。这与 Z 的含义相同。所以这部分是多余的。我建议您向数据发布者介绍标准 ISO 8601 格式。无需发明输入中看到的格式。

字符串操作而不是自定义格式化程序

如果您的所有输入都具有相同的 +0000Z 结尾,我建议您清理传入数据而不是定义格式化模式。

String input = "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ;
Instant instant = Instant.parse( input ) ;

其他格式

您稍后发表评论

"2017-01-04T12:30:00-05:00" 、 "2017-03-20T22:05:00Z" 等。所以我不能假设我的所有输入都具有相同的 +0000Z 结尾。< /p>

这两个都是标准的 ISO 8601 格式。两者都可以解析为 OffsetDateTime 对象按原样,无需更改。

因此,我仍然认为,考虑到可能的输入范围,最简单的方法是执行 replace 首先进行字符串操作,其中没有如果你的其他两种格式有效 到达。然后将所有三个变体解析为 OffsetDateTime 对象。有时,程序员往往会过度思考问题,并过度设计复杂的解决方案,而一个简单的解决方案就足够了。

示例代码:

OffsetDateTime odt1 = OffsetDateTime.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( "2017-01-04T12:30:00-05:00".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt3 = OffsetDateTime.parse( "2017-03-20T22:05:00Z".replace( "+0000Z" , "Z" ) ) ;

2022-03-12T03:59:59Z

2017-01-04T12:30-05:00

2017-03-20T22:05Z

请参阅此 代码在 IdeOne.com 上实时运行

解析时捕获 DateTimeParseException 以检测另一种意外格式。

当然,最好的解决方案是教育数据发布者如何一致使用 ISO 8601 格式(例如后两个示例),同时避免使用第一个示例的古怪格式。

从纪元开始计数

我建议不要将时间作为从纪元开始计数的方式进行跟踪。这样的计数本质上是不明确的并且容易出错。相反,请使用标准 ISO 8601 格式的文本。但如果你坚持要数的话,就在这里。

要获取自 1970-01-01T00:00Z 纪元引用以来的秒数,请从 OffsetDateTime 中提取 Instant 并进行询问。

long secondsSinceEpoch = odt.toInstant().getEpochSecond() ;

tl;dr

Your input happens to be a screwy variation of the standard IS0 8601 format used by default with the java.time.Instant class. Fix your input string, and parse.

Instant.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) )

Or, reformatted:

Instant.parse
( 
    "2022-03-12T03:59:59+0000Z"
    .replace( "+0000Z" , "Z" ) 
)

See this code run live at IdeOne.com.

2022-03-12T03:59:59Z

But the very best solution is to use only ISO 8601 formats when exchanging date-time values.

Details

ZonedDateTime inappropriate here

ZonedDateTime is the wrong class for your input. Your input has a Z which is a standard abbreviation for an offset from UTC of zero hours-minutes-seconds. But no time zone indicated, only a mere offset. So use OffsetDateTime or Instant rather than ZonedDateTime.

+0000 and Z redundant

The +0000 also means an offset of zero hours-minutes-seconds. This is the same meaning as the Z. So this part is redundant. I suggest you educate the publisher of your data about the standard ISO 8601 formats. No need to invent formats such as seen in your input.

String manipulation rather than custom formatter

If all your inputs have the same ending of +0000Z, I suggest you clean the incoming data rather than define a formatting pattern.

String input = "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ;
Instant instant = Instant.parse( input ) ;

Other formats

You later commented:

"2017-01-04T12:30:00-05:00" , "2017-03-20T22:05:00Z", etc. So I cannot assume all my inputs to have the same ending of +0000Z.

Both of those are standard ISO 8601 formats. Both can be parsed as OffsetDateTime objects as-is, without alteration.

So I still maintain that the simplest approach, given your range of possible inputs, is to do the replace string manipulation first, which has no effect if your other two formats arrive. Then parse all three variations as OffsetDateTime objects. Sometimes programmers tend to over-think a problem, and over-engineer an elaborate solution where a simple one suffices.

Example code:

OffsetDateTime odt1 = OffsetDateTime.parse( "2022-03-12T03:59:59+0000Z".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( "2017-01-04T12:30:00-05:00".replace( "+0000Z" , "Z" ) ) ;
OffsetDateTime odt3 = OffsetDateTime.parse( "2017-03-20T22:05:00Z".replace( "+0000Z" , "Z" ) ) ;

2022-03-12T03:59:59Z

2017-01-04T12:30-05:00

2017-03-20T22:05Z

See this code run live at IdeOne.com.

Trap for DateTimeParseException while parsing to detect yet another unexpected format.

Of course, the best solution is to educate the publisher of your data about consistent use of ISO 8601 formats such as the latter two examples, while avoiding the screwy first example’s format.

Count since epoch

I recommend against tracking time as a count-since-epoch. Such a count is inherently ambiguous and error-prone. Instead, use text in standard ISO 8601 format. But if you insist on a count, here it is.

To get a count of seconds since the epoch reference of 1970-01-01T00:00Z, extract a Instant from the OffsetDateTime, and interrogate.

long secondsSinceEpoch = odt.toInstant().getEpochSecond() ;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文