英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论