0

我有这个字符串

2020 年 8 月 7 日星期五 18:00:00 +0000

我需要将其转换为 LocalDateTime

我尝试了几种方法:

创建一个 DateTimeFormatter 并解析字符串

String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss", Locale.getDefault());
LocalDateTime parsedDate = LocalDateTime.parse(publishedString, formatter);

使用 SimpleDateFormat 将其转换为 Date,然后将 resultDate 转换为 LocalDateTime

String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
SimpleDateFormat dateFormatter = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z");
Date date = dateFormatter.parse(publishedString);
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

两种解决方案都给了我同样的例外:

java.time.format.DateTimeParseException: Text 'Fri, 07 Aug 2020 18:00:00 +0000' could not be parsed 
at index 0 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)

如何转换该字符串?

4

3 回答 3

4

tl;博士

OffsetDateTime.parse( 
    "Fri, 07 Aug 2020 18:00:00 +0000" , 
    DateTimeFormatter.RFC_1123_DATE_TIME 
)

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

LocalDateTime是错误的类

您的输入字符串包含+0000表示与 UTC 的偏移量。

所以你不应该使用LocalDateTime. 该类故意缺少任何时区或偏移量的概念。有了LocalDateTime,您的字符串Fri, 07 Aug 2020 18:00:00 +0000将在 2020 年 8 月 7 日变为 6M,但我们不知道那是日本东京下午 6 点、法国图卢兹下午 6 点,还是美国俄亥俄州托莱多下午 6 点——所有不同的时刻相隔几个小时。

OffsetDateTime

相反,这个值应该被解析为OffsetDateTime.

解析

您输入的格式是RFC 1123的格式。该特定格式是在java.time中预定义的。

String input = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter f = DateTimeFormatter.RFC_1123_DATE_TIME;
OffsetDateTime odt = OffsetDateTime.parse( input , f );

odt.toString(): 2020-08-07T18:00Z

于 2020-08-07T19:43:08.587 回答
3

我会说使用 Locale.ROOT 并且不要忘记 DateTimeFormatter 类中的 Z

String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss Z", Locale.ROOT);
LocalDateTime parsedDate = LocalDateTime.parse(dateString, formatter);
于 2020-08-06T16:55:39.007 回答
3

我了解您需要一个LocalDateTimeAPI,由于您无法控制的设计问题正在尝试使用LocalDateTime某个时间点。

如果外部合同规定LocalDateTime要理解哪个时区或 UTC 偏移量LocalDateTime,那么至少在 99.977 % 的情况下可以使其工作。在某些同事程序员不阅读合同的那一天,您仍然会等待发生编程错误,这是我们无法在代码中解决的问题,只能尝试通过良好的注释来缓解。

例如,如果合约显示 UTC,那么我们需要确保将时间转换为 UTC。为此,我们需要字符串的偏移量。

    ZoneOffset contractualOffset = ZoneOffset.UTC;
    String stringWeveGot = "Fri, 07 Aug 2020 18:00:00 +0000";
    LocalDateTime convertedDateTime = OffsetDateTime
            .parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME)
            .withOffsetSameInstant(contractualOffset)
            .toLocalDateTime();
    System.out.println(convertedDateTime);

输出:

2020-08-07T18:00

如果字符串中的偏移量已经被要求为 0,则需要验证它是否是,否则错误将被忽视,用户将得到错误的结果。例如:

    OffsetDateTime parsedOdt = OffsetDateTime
            .parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME);
    if (! parsedOdt.getOffset().equals(contractualOffset)) {
        throw new IllegalStateException("Offset must be " + contractualOffset
                + ", was " + parsedOdt.getOffset());
    }
    LocalDateTime convertedDateTime = parsedOdt.toLocalDateTime();

如果合同提到某个时区,则转换为该时区。我以澳大利亚/维多利亚为例。

    ZoneId contractualZone = ZoneId.of("Australia/Victoria");
    String stringWeveGot = "Fri, 07 Aug 2020 18:00:00 +0000";
    LocalDateTime convertedDateTime = OffsetDateTime
            .parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME)
            .atZoneSameInstant(contractualZone)
            .toLocalDateTime();
    System.out.println(convertedDateTime);

2020-08-08T04:00

在时钟倒转的时间异常情况下,您将得到一个模棱两可的结果,例如在夏令时 (DST) 结束时的倒退。

你的代码出了什么问题?

此处解释了您的异常的原因:

于 2020-08-09T06:41:31.740 回答