java.text.ParseException: Nicht parsbares Datum: java.text.DateFormat.parse(DateFormat.java:579)

Lesezeit: 6 Minuten

javatextParseException Nicht parsbares Datum
Piotr

Ich habe ein Problem mit SimpleDateFormat.

SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.getDefault());
Date dt=dtfmt.parse(deptdt);

Im Android-Emulator funktioniert es gut, aber im Telefon habe ich diesen Fehler:

W/System.err: java.text.ParseException: Unparseable date: “24 Oct 2016 7:31 pm” (bei Offset 3) W/System.err: at java.text.DateFormat.parse(DateFormat.java:579)

Irgendeine Lösungsmöglichkeit?

Benutze niemals SimpleDateFormat oder DateTimeFormatter ohne ein Locale

Da die angegebene Datumszeit auf Englisch ist, sollten Sie verwenden Locale.ENGLISH mit Ihrem Datum-Uhrzeit-Parser; Andernfalls schlägt die Analyse in einem System (Computer, Telefon usw.) fehl, das eine nicht englische Art von Gebietsschema verwendet.

Beachten Sie außerdem, dass die Date-Time-API von java.util und ihre Formatierungs-API, SimpleDateFormat sind veraltet und fehleranfällig. Es wird empfohlen, die Verwendung vollständig einzustellen und auf die umzusteigen moderne Datum-Uhrzeit-API.

  • Wenn Sie sich aus irgendeinem Grund an Java 6 oder Java 7 halten müssen, können Sie verwenden ThreeTen-Backport die die meisten zurückportiert java.time Funktionalität zu Java 6 & 7.
  • Wenn Sie für ein Android-Projekt arbeiten und Ihr Android-API-Level immer noch nicht mit Java-8 kompatibel ist, überprüfen Sie dies Java 8+ APIs verfügbar durch Desugaring und How to use ThreeTenABP in Android Project.

Demo:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "24 Oct 2016 7:31 pm";
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             // For case-insensitive (e.g. am, Am, AM) parsing 
                .appendPattern("d MMM uuuu h:m a")  // Pattern conforming to the date-time string
                .toFormatter(Locale.ENGLISH);       // Locale
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);
    }
}

Ausgabe:

2016-10-24T19:31

Standardmäßig, DateTimeFormatter#ofPattern nutzt die standardmäßiges FORMAT-Gebietsschema die die JVM während des Starts basierend auf der Hostumgebung festlegt. Gleiches gilt für SimpleDateFormat. Ich habe versucht, das Problem durch die folgende Demo zu veranschaulichen:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        final String strDateTime = "24 Oct 2016 7:31 pm";           
        DateTimeFormatter dtfWithDefaultLocale = null;          

        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));

        // Setting the JVM's default locale to Locale.FRANCE
        Locale.setDefault(Locale.FRANCE);
        
        // Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
        DateTimeFormatter dtfWithEnglishLocale = getDateTimeFormatterWithEnglishLocale();
        System.out.println("JVM's Locale: " + Locale.getDefault());
        System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
        LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
        System.out.println("Parsed with Locale.ENGLISH: " + zdt);

        
        System.out.println("JVM's Locale: " + Locale.getDefault());
        // Using DateTimeFormatter with the default Locale
        dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
        System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
        System.out.println(
                "Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
    }
    
    static DateTimeFormatter getDateTimeFormatterWithDefaultLocale() {
        return new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             
                .appendPattern("d MMM uuuu h:m a") 
                .toFormatter(); // Using default Locale
    }
    
    static DateTimeFormatter getDateTimeFormatterWithEnglishLocale() {
        return new DateTimeFormatterBuilder()
                .parseCaseInsensitive()             
                .appendPattern("d MMM uuuu h:m a") 
                .toFormatter(Locale.ENGLISH); // Using Locale.ENGLISH
    }
}

Ausgabe:

JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text '24 Oct 2016 7:31 pm' could not be parsed at index 3
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
    at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
    at Main.main(Main.java:34)

Die folgende Demo, mit SimpleDateFormatnur der Vollständigkeit halber:

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 {
        final String strDateTime = "24 Oct 2016 7:31 pm";
        SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy h:m a", Locale.ENGLISH);
        Date date = sdf.parse(strDateTime);
        System.out.println(date);
    }
}

Ausgabe:

Mon Oct 24 19:31:00 BST 2016

Dein deptdt enthält Oct was wie ein englischer Monatsname aussieht. Aber dein Locale.getDefault() gibt wahrscheinlich ein nicht-englisches Gebietsschema an. Ersetzen Sie es durch Locale.ENGLISH oder Locale.US:

SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt=dtfmt.parse(deptdt);

Es passiert wahrscheinlich, weil das Standardgebietsschema des Telefons nicht Englisch ist und der Monatsname in Ihrer Eingabe (Oct).

Die Lösung besteht darin, explizit das englische Gebietsschema zu verwenden:

SimpleDateFormat dtfmt = new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt = dtfmt.parse("24 Oct 2016 7:31 pm");

Anstatt direkt mit zu arbeiten SimpleDateFormat (da diese alte API viele Probleme und Designprobleme hat), können Sie die verwenden ThreeTen Backport, ein großartiger Backport für die neuen Datums-/Uhrzeitklassen von Java 8. Um es zu verwenden AndroidSie benötigen auch die ThreeTenABP (mehr zur Verwendung hier).

Die wichtigsten zu verwendenden Klassen sind org.threeten.bp.LocalDateTime (Es scheint die beste Wahl zu sein, da Sie Datums- und Zeitfelder in Ihrer Eingabe haben) und org.threeten.bp.format.DateTimeFormatter (um die Eingabe zu analysieren). benutze ich auch java.util.Locale Klasse, um sicherzustellen, dass die Monatsnamen auf Englisch analysiert werden, und die org.threeten.bp.format.DateTimeFormatterBuilder um sicherzustellen, dass es analysiert wird pm (Machen Sie Groß- und Kleinschreibung unabhängig, da dies standardmäßig der Fall ist PM):

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // case insensitive to parse "pm"
    .parseCaseInsensitive()
    // pattern
    .appendPattern("dd MMM yyyy h:mm a")
    // use English locale to parse month name (Oct)
    .toFormatter(Locale.ENGLISH);
// parse input
LocalDateTime dt = LocalDateTime.parse("24 Oct 2016 7:31 pm", fmt);
System.out.println(dt); // 2016-10-24T19:31

Die Ausgabe wird sein:

2016-10-24T19:31

Wenn Sie dies in a umwandeln müssen java.util.Datedu kannst den … benutzen org.threeten.bp.DateTimeUtils Klasse. Aber Sie müssen auch wissen, welche Zeitzone verwendet wird, um dies zu konvertieren. Im folgenden Beispiel verwende ich “UTC”:

Date date = DateTimeUtils.toDate(dt.atZone(ZoneOffset.UTC).toInstant());

Um in eine andere Zone zu wechseln, können Sie Folgendes tun:

Date date = DateTimeUtils.toDate(dt.atZone(ZoneId.of("Europe/London")).toInstant());

Beachten Sie, dass die API verwendet IANA-Zeitzonennamen (immer im Format Continent/Citywie America/Sao_Paulo oder Europe/Berlin). Vermeiden Sie die Verwendung von 3-Buchstaben-Abkürzungen (wie z CST oder PST), weil sie mehrdeutig und nicht standardisiert sind. Um die Zeitzone zu finden, die besser zu jeder Region passt, verwenden Sie die ZoneId.getAvailableZoneIds() Methode und prüfen Sie, welche für Ihre Anwendungsfälle am besten geeignet ist.

PS: das letzte Beispiel oben (dt.atZone(ZoneId.of("Europe/London"))) erstellt das Datum/die Uhrzeit 2016-10-24T19:31 in der Londoner Zeitzone. Aber wenn was du willst 2016-10-24T19:31 in UTC, konvertieren Sie es dann in eine andere Zeitzone, dann sollten Sie Folgendes tun:

Date date = DateTimeUtils.toDate(dt
    // first convert it to UTC
    .toInstant(ZoneOffset.UTC)
    // then convert to LondonTimezone
    .atZone(ZoneId.of("Europe/London")).toInstant());

1001780cookie-checkjava.text.ParseException: Nicht parsbares Datum: java.text.DateFormat.parse(DateFormat.java:579)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy