wake-up-neo.com

Android parse String to Date - unbekanntes Musterzeichen 'X'

Ich habe Service Datumszeichenfolge aus dem Web abrufen und dann in Date object pare Aber irgendwie stürzt die Anwendung ab .. Dies ist meine Zeichenfolge, die ich analysiere: 2015-02-05T05:20:02+00:00

onStartCommand ()

String datetime = "2015-02-05T05:20:02+00:00";
Date new_date = stringToDate(datetime);

stringToDate ()

private Date stringToDate(String s){
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    try{
        return df.parse(s);
    }catch(ParseException e){
        e.printStackTrace();
    }
    return null;
}

LogCat:

02-06 20:37:02.008: E/AndroidRuntime(28565): FATAL EXCEPTION: main
02-06 20:37:02.008: E/AndroidRuntime(28565): Process: com.dotmav.runescapenotifier, PID: 28565
02-06 20:37:02.008: E/AndroidRuntime(28565): Java.lang.RuntimeException: Unable to start service [email protected] with Intent { cmp=com.dotmav.runescapenotifier/.GEService }: Java.lang.IllegalArgumentException: Unknown pattern character 'X'
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.app.ActivityThread.handleServiceArgs(ActivityThread.Java:2881)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.app.ActivityThread.access$2100(ActivityThread.Java:144)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1376)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.os.Handler.dispatchMessage(Handler.Java:102)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.os.Looper.loop(Looper.Java:135)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.app.ActivityThread.main(ActivityThread.Java:5221)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.lang.reflect.Method.invoke(Native Method)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.lang.reflect.Method.invoke(Method.Java:372)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:899)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:694)
02-06 20:37:02.008: E/AndroidRuntime(28565): Caused by: Java.lang.IllegalArgumentException: Unknown pattern character 'X'
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.Java:314)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.Java:303)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.text.SimpleDateFormat.<init>(SimpleDateFormat.Java:356)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Java.text.SimpleDateFormat.<init>(SimpleDateFormat.Java:249)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at com.dotmav.runescapenotifier.GEService.stringToDate(GEService.Java:68)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at com.dotmav.runescapenotifier.GEService.onStartCommand(GEService.Java:44)
02-06 20:37:02.008: E/AndroidRuntime(28565):    at Android.app.ActivityThread.handleServiceArgs(ActivityThread.Java:2864)
02-06 20:37:02.008: E/AndroidRuntime(28565):    ... 9 more

EDIT: onDestroy () Alarm für periodisches Update setzen ...

AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis() + (1000 * 60),
    PendingIntent.getService(this, 0, new Intent(this, GEService.class), 0)
);
36
Matjaž Mav

Entfernen Sie "XXX" von 

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");

und alles würde gut funktionieren.

Gehen Sie die Liste der Symbole durch, die in einem SimpleDateFormat-Konstruktor verwendet werden können. Dies ist die Dokumentation

Wahrscheinlich suchen Sie nach "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

Ändern Sie Ihren Code in 

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 

oder 

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // if timezone is required
24
Rohit5k2

Die Android-Version von SimpleDateFormat unterstützt das X-Muster nicht, sodass XXX nicht funktioniert. Stattdessen können Sie ZZZZZ verwenden, das dasselbe tut und die Zeitzone im Format +02:00 (oder -02:00 abhängig von der lokalen Zeitzone) ausgibt.

41
flawyte

Sie verwenden den falschen Datumsformatierer. 

Verwenden Sie stattdessen diese: DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

Ich denke, dass Android im Gegensatz zu Java 7 Z (wie in Java 6) für Zeitzonen und nicht für X verwendet. Verwenden Sie also this als Datumsformat.

11
Thanos

Da Z und XXX unterschiedlich sind, habe ich folgende Problemumgehung implementiert:

// This is a workaround from Z to XXX timezone format
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") {

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
        StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
        return rfcFormat.insert(rfcFormat.length() - 2, ":");
    }

    @Override
    public Date parse(String text, ParsePosition pos) {
        if (text.length() > 3) {
            text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
        }
        return super.parse(text, pos);
    }
}
7
Alexander K

Niemand hat erwähnt, dass dieser Fehler auf pre-Nougat-Geräten auftrat. Ich dachte, meine Antwort zu teilen. Vielleicht ist es hilfreich für diejenigen, die diesen Thread erreicht haben. 

Diese Antwort erwähnt zu Recht, dass "X" nur für Nougat + -Geräte unterstützt wird. Ich sehe immer noch, dass documentation die Verwendung von "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" vorschlägt und nicht sicher ist, warum sie diesen Punkt nicht explizit machen. 

Für mich funktionierte yyyy-MM-dd'T'HH:mm:ssXXX gut, bis ich versuche, es auf einem 6.0-Gerät zu testen, und es begann zu stürzen, was mich dazu brachte, zu diesem Thema zu recherchieren. Das Ersetzen durch yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ hat das Problem behoben und funktioniert auf allen 5.0 und höher. 

6
Wahib Ul Haq

Android SimpleDateFormat unterscheidet sich von Java 7 SDK und unterstützt nicht "X", um ISO 8601 zu parsen. Sie können die Z- oder ZZZZZ-Formatvorlagen verwenden, um die Zeitzone auf UTC zu formatieren und programmatisch festzulegen. Hier ist eine util-Klasse:

public class DateUtil {

    public static final String iso8601DatePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";
    public static final DateFormat iso8601DateFormat = new SimpleDateFormat(iso8601DatePattern);
    public static final TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");

    static {
        iso8601DateFormat.setTimeZone(utcTimeZone);
    }

    public static String formatAsIso8601(Date date) {

        return iso8601DateFormat.format(date);
    }
}
6
Narek

Der Fehler besagt, dass simpleDateFormat das Zeichen X nicht erkennt. Wenn Sie Millisekunden suchen, wird es mit dem Zeichen S dargestellt.

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
2
Adam W

tl; dr

long millisecondsSinceEpoch = OffsetDateTime.parse( "2015-02-05T05:20:02+00:00" ).plusHour( 1 ).toInstant().toEpochMilli()  // Warning: Possible loss of data in truncating nanoseconds to milliseconds. But not in this particular case.

Einzelheiten

Andere Antworten sind korrekt, aber jetzt veraltet. Die alten Datum-Uhrzeit-Klassen sind jetzt veraltet. Verwenden Sie stattdessen Java.time-Klassen.

ISO 8601

Die Eingabezeichenfolge hat das Standardformat ISO 8601. Direkte Analyse, keine Notwendigkeit, ein Formatierungsmuster zu definieren, da die Java.time-Klassen standardmäßig ISO 8601-Formate verwenden.

OffsetDateTime

Die Eingabe enthält einen Offset-von-UTC mit dem +00:00, sodass wir als OffsetDateTime -Objekt parsen können.

String input = "2015-02-05T05:20:02+00:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input );

Mathematik

Wenn Sie eine Stunde oder eine Minute später hinzufügen möchten, um einen Alarm einzustellen, rufen Sie die plus-Methoden auf.

OffsetDateTime minuteLater = odt.plusMinutes( 1 );
OffsetDateTime hourLater = odt.plusHours( 1 );

Durchlaufen Sie die Instant-Klasse, um eine Anzahl von Millisekunden zu erhalten. Die Instant -Klasse repräsentiert einen Moment auf der Timeline in UTC mit einer Auflösung von Nanosekunden . Die Abfrage nach Millisekunden bedeutet möglicher Datenverlust, da die neun Stellen einer Dezimalfraktion auf die drei Ziffern der Dezimalfraktion gekürzt werden.

long millisecondsSinceEpoch = odt.toInstant().toEpochMilli();  // Warning: Possible loss of data in truncating nanoseconds to milliseconds.

Über Java.time

Das Java.time -Framework ist in Java 8 und höher integriert. Diese Klassen ersetzen die alten störenden Datum-Zeit-Klassen wie Java.util.Date, .Calendar und & Java.text.SimpleDateFormat

Das Joda-Time - Projekt, jetzt im Wartungsmodus , empfiehlt die Migration zu Java.time.

Weitere Informationen finden Sie im Oracle Tutorial . In Stack Overflow finden Sie viele Beispiele und Erklärungen.

Ein Großteil der Java.time-Funktionalität wird auf Java 6 & 7 in ThreeTen-Backport und weiter auf Android in ThreeTenABP angepasst.

Das ThreeTen-Extra -Projekt erweitert Java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Erweiterungen von Java.time. 

1
Basil Bourque

Verwenden Sie eine SimpleDateFormat, um eine korrekt formatierte String-Ausgabe zu erzeugen:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

String formattedNow = simpleDateFormat.format(new Date(System.currentTimeMillis()));

Ausgabe: 2018-02-27T07:36:47.686Z

1
suhasini

Einfache Lösung: 

Verwende diesen yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ 

Stattdessen von yyyy-MM-dd'T'HH:mm:ss.SSSXXX

Erledigt.

1
Hiren Patel

Die folgende Klasse kann verwendet werden, um die Zeichenfolge in ein Datum umzuwandeln, wenn Pattern dies nicht kennt.

    import Java.text.SimpleDateFormat;
    import Java.util.Arrays;
    import Java.util.Date;
    import Java.util.List;

/**
 * StringToDateFormater is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for
 * formatting (date → text), parsing (text → date), and normalization.
 * 
 * This class is mainly used for convert the date from string. It should be used only when date pattern doesn't aware of
 * it. 
 *
 */
public class StringToDateFormater extends SimpleDateFormat {

    private static final List<String> DATE_SUPPORTED_FORMAT_LIST = Arrays.asList("yyyyMMddHHmmss", "yyyyMMddHHmm",
            "yyyyMMddHHmm", "yyyyMMddHH", "yyyyMMdd", "yyyyMMddHHmmssSS");

    /**
     * 
     */
    private static final long serialVersionUID = -1732857502488169225L;

    /**
     * @param pattern
     */
    public StringToDateFormater() {
    }

    @Override
    public Date parse(String source) {
        Date date = null;

        SimpleDateFormat dateFormat = null;
        for (String format : DATE_SUPPORTED_FORMAT_LIST) {
            dateFormat = new SimpleDateFormat(format);
            try {
                return dateFormat.parse(source);
            } catch (Exception exception) {

            }

        }

        return date;
    }
}
0
Sudhakar