简体   繁体   中英

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 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 . 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 .

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

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"

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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