将字符串转换为Java中的LocalDateTime

huangapple go评论82阅读模式
英文:

Convert String to LocalDateTime in Java

问题

我有这个字符串
> Fri, 07 Aug 2020 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(dateString, formatter);

将其转换为Date并使用SimpleDateFormat,然后将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(dateString);
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)

我该如何将该字符串转换?

英文:

I have this String
> Fri, 07 Aug 2020 18:00:00 +0000

And I need to convert it to a LocalDateTime

I tryed several ways:

create a DateTimeFormatter and parse the String

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

Convert it to a Date with a SimpleDateFormat and then convert the resultDate to a 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();

both solution gives me the same exception:

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)

How can I convert that String?

答案1

得分: 5

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

# `LocalDateTime` is the wrong class

Your input string contains `+0000` which indicates an offset-from-UTC. 

So you should not be using `LocalDateTime`. That class purposely lacks any concept of time zone or offset. With `LocalDateTime`, your string `Fri, 07 Aug 2020 18:00:00 +0000` will become 6M on August 7th 2020, but we won't know if that is 6 PM in Tokyo Japan, 6 PM in Toulouse France, or 6 PM in Toledo Ohio US  all different moments several hours apart.

# `OffsetDateTime`

Instead, this value should be parsed as [`OffsetDateTime`][2].

# Parsing

Your input's format is that of [RFC 1123][3]. That particular format is predefined in *java.time*. 

```java
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


<details>
<summary>英文:</summary>

# tl;dr

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

See this [code run live at IdeOne.com][1].

# `LocalDateTime` is the wrong class

Your input string contains `+0000` which indicates an offset-from-UTC. 

So you should not be using `LocalDateTime`. That class purposely lacks any concept of time zone or offset. With `LocalDateTime`, your string `Fri, 07 Aug 2020 18:00:00 +0000` will become 6M on August 7th 2020, but we won&#39;t know if that is 6 PM in Tokyo Japan, 6 PM in Toulouse France, or 6 PM in Toledo Ohio US — all different moments several hours apart.

# `OffsetDateTime`

Instead, this value should be parsed as [`OffsetDateTime`][2].

# Parsing

Your input&#39;s format is that of [RFC 1123][3]. That particular format is predefined in *java.time*. 

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

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

答案2

得分: 4

我建议使用 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);
英文:

I'd say use Locale.ROOT and don't forget the Z in the DateTimeFormatter class

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

答案3

得分: 3

我明白你需要一个LocalDateTime,用于处理一个API的需求,该API由于你无法控制的设计问题,正试图使用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,您需要验证它是否为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)结束时,您将得到一个模糊的结果。

关于你的代码出了什么问题?你的异常的原因在这里解释了:

英文:

I understand that you need a LocalDateTime for an API that due to a design problem beyond your control is trying to use LocalDateTime for a point in time.

If an external contract dictates in which time zone or at which UTC offset the LocalDateTime is to be understood, LocalDateTime can be made to work, at least for 99.977 % of cases. You will still have a programming error waiting to happen on the day when some colleague programmer does not read the contract, a problem that we cannot solve in the code, only try to mitigate through good commenting.

If for example the contract says UTC, then we need to make sure we convert the time to UTC. And we need the offset from the string for doing so.

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

Output:

> 2020-08-07T18:00

If the offset in the string is required to be 0 already, you need to validate that it is, or errors will go unnoticed and users will get wrong results. For example:

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

If the contract mentions some time zone, convert to that time zone. I am taking Australia/Victoria as an example.

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

> 2020-08-08T04:00

You will get an ambiguous result at time anomalies where the clock is turned backward, for example at the fall back when summer time (DST) ends.

What went wrong in your code?

The cause of your exception is explained here:

huangapple
  • 本文由 发表于 2020年8月7日 00:37:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63288135.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定