Sure, here’s the translation: Java字符串转日期格式

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

Java String to Date format

问题

我有以下日期的String,我试图解析并格式化为2021年9月21日,但出现了ParsingException

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
System.out.println(expiryDate);
Date formatter = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy").parse(expiryDate);
Exception in thread "main" java.text.ParseException:
Unparseable date: "Tue Sep 21 12:11:37 PHT 2021"
	at java.base/java.text.DateFormat.parse(DateFormat.java:395)

我猜日期解析格式不正确,但无法找出正确的格式。

英文:

I have below String of date that I'm trying to parse and format to Sept 21 2021 but having ParsingException:

String expiryDate ="Tue Sep 21 12:11:37 PHT 2021";
System.out.println(expiryDate);
Date formatter = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy").parse(expiryDate);
Exception in thread "main" java.text.ParseException:
Unparseable date: "Tue Sep 21 12:11:37 PHT 2021"
	at java.base/java.text.DateFormat.parse(DateFormat.java:395)

I guess I have incorrect parsing date format but can't figure out the correct one.

答案1

得分: 4

我认为你的问题是在你的SimpleDateFormat中缺少了Locale设置。如果你不明确设置一个,代码可能会使用默认的Locale,这可能不是ENGLISH,而是其他地方的,可能是在菲律宾的计算机上。例如,它会尝试解析Tue的菲律宾缩写,这将导致一个无法解析的String

这是在我的计算机上成功运行的代码(也不是ENGLISH),在遇到与你相同的Exception之后:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH)
				.parse(expiryDate);
System.out.println(date.toString());

这将产生以下输出:

Tue Sep 21 06:11:37 CEST 2021

这也适用于只包含一个E的模式。

Java 8 - 10的解决方案使用java.time

这在Java 8和10上成功运行,但根据@ArvindKumarAvinash的答案 ,这在Java 11及可能更高版本中不起作用,因为String expiryDate中时区的缩写。

你可以像这样在java.time中做:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
															Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
System.out.println("Something will expire at " + zdt);

这将输出:

Something will expire at 2021-09-21T12:11:37+08:00[Asia/Manila]

可以通过另一个DateTimeFormatter来更改输出格式,要么使用内置的DateTimeFormatter.ISO_ZONED_DATE_TIME,要么通过.ofPattern(pattern, Locale.ENGLISH)或使用DateTimeFormatterBuilder创建自定义格式。

考虑到你的要求,只需要格式化和输出日期部分,你可以选择在java.time中简单提取日期部分(这是LocalDate)并进行格式化:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
															Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
LocalDate expiryLocalDate = zdt.toLocalDate();
System.out.println("Something will expire at "
					+ expiryLocalDate.format(DateTimeFormatter.ofPattern("MMM dd uuuu",
																		Locale.ENGLISH)));

将输出:

Something will expire at Sep 21 2021

Trails中了解更多关于java.time的信息。

英文:

I think your problem is the missing Locale in your SimpleDateFormat. If you don't explicitly set one, the code may use your default Locale, which then might not be ENGLISH but something else, which is likely to be on a computer located on the Philipines. It would try to parse the Philipine abbreviation for Tue, for example, and that leads to an unparseable String.

Here is what worked on my computer (also not ENGLISH) after having got the same Exception as you:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH)
				.parse(expiryDate);
System.out.println(date.toString());

This gave the following output:

Tue Sep 21 06:11:37 CEST 2021

This worked with a pattern having just one E as well.


Java 8 - 10 solution with java.time:

This successfully runs on Java 8 and 10, but according to the answer by @ArvindKumarAvinash, this won't work in Java 11 and possibly the versions above due to the abbreviation of the time zone in the String expiryDate.

You could do it like this in java.time:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
															Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
System.out.println("Something will expire at " + zdt);

and it would output

Something will expire at 2021-09-21T12:11:37+08:00[Asia/Manila]

Changing the output format can be done via another DateTimeFormatter, either use a built-in one as DateTimeFormatter.ISO_ZONED_DATE_TIME or create a custom one by .ofPattern(pattern, Locale.ENGLISH) or using a DateTimeFormatterBuilder.

Considering your requirement to format and output the date part only, you have the option to simply extract the date part (that's a LocalDate) and format that in java.time:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
															Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
LocalDate expiryLocalDate = zdt.toLocalDate();
System.out.println("Something will expire at "
					+ expiryLocalDate.format(DateTimeFormatter.ofPattern("MMM dd uuuu",
																		Locale.ENGLISH)));

will output

Something will expire at Sep 21 2021

Read more about java.time in the Trails.

答案2

得分: 1

The answer by deHaar is brilliant but that fails with Java-11. A safe option will be to replace PHT with the corresponding Zone-Offset value.

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
        OffsetDateTime odt = OffsetDateTime.parse(expiryDate,
                DateTimeFormatter.ofPattern("EEE MMM d H:m:s ZZZZ u", Locale.ENGLISH));
        System.out.println(odt);

        // Custom format
        String formatted = odt.format(DateTimeFormatter.ofPattern("EEEE MMMM dd uuuu 'at' hh:mm:ss a", Locale.ENGLISH));
        System.out.println(formatted);
    }
}

Output:

2021-09-21T12:11:37+08:00
Tuesday September 21 2021 at 12:11:37 PM

Note: java.util date-time classes are outdated and error-prone and so is their formatting API, SimpleDateFormat. I suggest you should stop using them completely and switch to the modern date-time API.

If you are doing it for your Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Learn more about the modern date-time API at Trail: Date Time.

With legacy API:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
        Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZ yyyy").parse(expiryDate);
        System.out.println(date);

        // Custom format
        String formatted = new SimpleDateFormat("EEEE MMMM dd yyyy 'at' hh:mm:ss a", Locale.ENGLISH).format(date);
        System.out.println(formatted);
    }
}
英文:

The answer by deHaar is brilliant but that fails with Java-11. A safe option will be to replace PHT with the corresponding Zone-Offset value.

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
	public static void main(String[] args) {
		String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
		OffsetDateTime odt = OffsetDateTime.parse(expiryDate,
				DateTimeFormatter.ofPattern("EEE MMM d H:m:s ZZZZ u", Locale.ENGLISH));
		System.out.println(odt);

		// Custom format
		String formatted = odt.format(DateTimeFormatter.ofPattern("EEEE MMMM dd uuuu 'at' hh:mm:ss a", Locale.ENGLISH));
		System.out.println(formatted);
	}
}

Output:

2021-09-21T12:11:37+08:00
Tuesday September 21 2021 at 12:11:37 PM

Note: java.util date-time classes are outdated and error-prone and so is their formatting API, SimpleDateFormat. I suggest you should stop using them completely and switch to the modern date-time API.

If you are doing it for your Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Learn more about the modern date-time API at Trail: Date Time.

With legacy API:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
	public static void main(String[] args) throws ParseException {
		String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
		Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZ yyyy").parse(expiryDate);
		System.out.println(date);

		// Custom format
		String formatted = new SimpleDateFormat("EEEE MMMM dd yyyy 'at' hh:mm:ss a", Locale.ENGLISH).format(date);
		System.out.println(formatted);
	}
}

答案3

得分: 0

我在这里是新的,如果我做错了什么事情很抱歉。

“Tue”包含三个字符,格式应为

"EEE MMM dd HH:mm:ss z yyyy"
英文:

I'm new here, sorry if I did anything wrong.

The "Tue" contains three character and the format should be

"EEE MMM dd HH:mm:ss z yyyy"

答案4

得分: 0

解释

似乎菲律宾标准时间的缩写在 Java 10 之前是 PHT,而从 Java 11 开始是 PST。可以通过运行以下代码来观察这一点:

DateTimeFormatter zf = DateTimeFormatter.ofPattern("z", Locale.ROOT);
ZoneId zid = ZoneId.of("Asia/Manila");
System.out.println(zf.format(ZonedDateTime.now(zid)));

在 Java 9 上的输出:

PHT

在 Java 11 上的输出:

PST

起初我以为不同版本的 CLDR(Unicode通用区域设置数据存储库)是原因。但当我使用Java的原始区域数据(使用 -Djava.locale.providers=COMPAT 运行)时,我得到了相同的行为差异,所以我不太确定。

无论如何,如果有任何方法可以避免使用三个字母的时区缩写,你都不应该依赖它们。它们往往会产生歧义,并且没有标准化。因此,你真的无法确定会得到什么。

除此之外,关于为格式化程序指定区域设置的评论和答案也是正确的。

英文:

The explanation

It seems that the abbrevatiosn for Philipines Standard Time was PHT up to Java 10 whereas it’s PST from Java 11. One way to see this is running the following piece of code:

	DateTimeFormatter zf = DateTimeFormatter.ofPattern("z", Locale.ROOT);
	ZoneId zid = ZoneId.of("Asia/Manila");
	System.out.println(zf.format(ZonedDateTime.now(zid)));

Output on Java 9:

> PHT

Output on Java 11:

> PST

I thought at first that different versions of CLDR, the Unicode Common Locale Data Repository, was the reason. But when I use Java’s original locale data instead (running with -Djava.locale.providers=COMPAT), I get the same difference in behaviuour, so I am not so sure.

In any case you should not rely in three letter time zone abbreviaitons in the first place if there is any way you can avoid it. They tend to be ambiguous, and they are not standardized. So you really cannot be sure what you get.

Apart from that the comments and answers telling you to specify a locale for your formatter are correct too.

huangapple
  • 本文由 发表于 2020年10月13日 17:39:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/64332621.html
匿名

发表评论

匿名网友

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

确定