简体   繁体   English

Java 字符串转日期格式

[英]Java String to Date format

I have below String of date that I'm trying to parse and format to Sept 21 2021 but having ParsingException :我有以下日期String ,我试图将其解析并格式化为Sept 21 2021但有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.我想我的解析日期格式不正确,但无法找出正确的格式。

I think your problem is the missing Locale in your SimpleDateFormat .我认为您的问题是SimpleDateFormat缺少Locale 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.如果您没有明确设置,代码可能会使用您的默认Locale ,然后它可能不是ENGLISH而是其他东西,它可能位于菲律宾的计算机上。 It would try to parse the Philipine abbreviation for Tue , for example, and that leads to an unparseable String .例如,它会尝试解析Tue的菲律宾缩写,这会导致无法解析的String

Here is what worked on my computer (also not ENGLISH ) after having got the same Exception as you:在遇到与您相同的Exception后,这是在我的计算机上运行的(也不是ENGLISH ):

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.这也适用于只有一个E的模式。


Java 8 - 10 solution with java.time :带有java.time Java 8 - 10 解决方案:

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 .这在 Java 8 和 10 上成功运行,但根据@ArvindKumarAvinash 的回答,由于String expiryDate时区的缩写,这在 Java 11 和上述版本中可能String expiryDate

You could do it like this in java.time :你可以在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 .可以通过另一个DateTimeFormatter更改输出格式,或者使用内置的DateTimeFormatter.ISO_ZONED_DATE_TIME或通过.ofPattern(pattern, Locale.ENGLISH)或使用DateTimeFormatterBuilder创建自定义.ofPattern(pattern, Locale.ENGLISH)

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 :考虑到您只需要格式化和输出日期部分,您可以选择简单地提取日期部分(即LocalDate )并在java.timejava.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 .Trails 中阅读有关java.time更多信息。

The answer by deHaar is brilliant but that fails with Java-11. deHaar回答很精彩,但在 Java-11 中失败了。 A safe option will be to replace PHT with the corresponding Zone-Offset value .一个安全的选择是将 PHT 替换为相应的 Zone-Offset 值

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 .注意: java.util日期时间类已经过时且容易出错,它们的格式化 API SimpleDateFormat也是如此。 I suggest you should stop using them completely and switch to the modern date-time API .我建议您应该完全停止使用它们并切换到现代日期时间 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 .如果您正在为您的 Android 项目执行此操作,并且您的 Android API 级别仍然不符合 Java-8,请查看 通过脱糖可用的 Java 8+ API如何在 Android 项目中使用 ThreeTenABP

Learn more about the modern date-time API at Trail: Date Time .Trail: Date Time 中了解有关现代日期时间 API 的更多信息。

With legacy API:使用旧 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);
    }
}

I'm new here, sorry if I did anything wrong.我是新来的,如果我做错了什么,抱歉。

The "Tue" contains three character and the format should be “Tue”包含三个字符,格式应为

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

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:似乎菲律宾标准时间的缩写是 PHT 到 Java 10 而它是 Java 11 的 PST。查看它的一种方法是运行以下代码:

    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: Java 9 上的输出:

PHT PHT

Output on Java 11: Java 11 上的输出:

PST太平洋标准时间

I thought at first that different versions of CLDR, the Unicode Common Locale Data Repository, was the reason.起初我认为是 CLDR 的不同版本,即 Unicode 通用语言环境数据存储库,是原因。 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.但是当我使用 Java 的原始语言环境数据(使用-Djava.locale.providers=COMPAT运行)时,我在行为上得到了相同的差异,所以我不太确定。

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.除此之外,告诉您为格式化程序指定语言环境的评论和答案也是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM