Android parse String to Date - unknown pattern character 'X'
I have Service
fetch date string from web and then I want to pare it to Date
object. But somehow application crashes.
This is my string that I'm parsing: 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 com.dotmav.runescapenotifier.GEService@384655b5 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() set alarm for periodical update...
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)
);
The Android version of SimpleDateFormat
doesn't support the X
pattern so XXX
won't work but instead you can use ZZZZZ
which does the same and outputs the timezone in format +02:00
(or -02:00
depending on the local timezone).
Remove "XXX" from
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
and everything would work fine.
Go through the list of symbols that can be used inside a SimpleDateFormat
constructor. Although the documentation shows the "XXX" format, this doesn't work on Android and will throw an IllegalArgumentException
.
Probably you are looking for "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
Change your code to
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
or
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // if timezone is required
No one has mentioned about this error occurring on pre-nougat devices so I thought to share my answer and maybe it is helpful for those who reached this thread because of it.
This answer rightly mentions that "X" is supported only for Nougat+ devices. I still see that documentation suggests to use "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
and not sure why they don't make this point explicit.
For me, yyyy-MM-dd'T'HH:mm:ssXXX
was working fine until I tried to test it on 6.0 device and it started crashing which led me to research on this topic. Replacing it with yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ
has resolved the issue and works on all 5.0+ devices.
You are using the wrong date formatter.
Use this instead: DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
I think that android in contrast with Java 7 uses Z (as in Java 6) for timezones and not X. So, use this for your date formats.
Since Z and XXX are different, I've implemented the following workaround:
// 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);
}
}