Unknown pattern character 'x', when using SimpleDateFormat
Asked Answered
E

6

11

Im trying to format a Date to String using SimpleDateFormat, and the pattern im using is this one

"yyyy-MM-dd'T'HH:mm:ss.SSSxxx"

but when reach this line

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSxxx");

i get the following exception:

java.lang.IllegalArgumentException: Unknown pattern character 'x' at java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.java:323) at java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.java:312) at java.text.SimpleDateFormat.(SimpleDateFormat.java:365) at java.text.SimpleDateFormat.(SimpleDateFormat.java:258)

the format im trying to achieve is "2017-06-16T12:19:59.001+02:00"

according to the documentation this pattern should work Whats wrong?

EDIT To clarify, i tried with xxx and XXX

in case of XXX i get java.lang.IllegalArgumentException: Unknown pattern character 'X'

Embus answered 16/6, 2017 at 11:42 Comment(6)
You attached pattern with uppercase X, while documentation tells that it should be lowercase x. But then exception stack tells about lowercase x again. Can you please clarify that?Obligation
The 'X' for the timezone is relatively new feature in SimpleDateFormat. If you run it on an Android version that support only Java 6 then it won't work.Rodmur
yes, but i tried both upper and lowercase.Embus
@BalázsNemes whats the alternative?Embus
You can use Z instead as the answer suggests it.Rodmur
I really have no idea. This is a completely valid question. As, as oppose to Java SE, old version of Android don't support X. I have no idea why people wanna down vote this question for no reason. I'm gonna give this question an up-vote.Swinney
O
26

See Update below.

Unfortunately, regarding uppercase X, the documentation [was at the time of the question and this answer] wrong. Since the documentation seems to have changed significantly regarding x and X, I'll go ahead and state here that right now, it says X (uppercase) is supported (since API level 1), but x (lowercase) is not mentioned at all. The docs used to not mention X either.

A check of the Android source code (see validateFormat()) shows that only the letters GyMdkHmsSEDFwWahKzZLc are recognized in that version, despite the docs' claim that X has been supported since API level 1. This explains why you're getting the IllegalArgumentException: Unknown pattern character 'X'.

See this bug report for historical details.

Meanwhile, you'll have to find a workaround, which will vary depending on what kind of input you need to parse. E.g. the OP's answer.

Update: X is available only from Nougat+.

The documentation has now been fixed to add a "Supported (API Levels)" column, which indicates that X is only supported starting from API level 24. Presumably the OP's IllegalArgumentException was due to testing the app on a pre-24 device, since the docs didn't say anything about supported API levels before.

Onesided answered 20/10, 2017 at 19:22 Comment(1)
I'm getting a warning about using "X" that claims my current min SDK would be 21 but it is 26. Really annoying...Clishmaclaver
E
20

I believe I found the answer in an issue at GitHub:

You are right, Android uses ZZZZZ instead to generate time zone like +01:00 (like XXX in Java). For now, could you try using the ApiClient#setDatetimeFormat method to customize the datetime format to make it work in Android?

Taking the petstore sample as an example:

// import io.swagger.client.Configuration;
// import io.swagger.client.ApiClient;
// import java.text.SimpleDateFormat;

// Customize for the default ApiClient
Configuration.getDefaultApiClient().setDatetimeFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"));

// Customize for a new ApiClient
ApiClient apiClient = new ApiClient();
apiClient.setDatetimeFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"));
// Use the new ApiClient
PetApi api = new PetApi(apiClient);
api.getPetById(new Long(1));

Apparently, I have to use:

yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ  
Embus answered 16/6, 2017 at 12:5 Comment(1)
this is solved my issue. I'm using regex to check is it ISO8601: regex101.com/r/b3GJso/1, then override parse(dateString) to use normalize string in the github url here, otherwise just use super.parse(dateString)Kagera
C
1

Use this instead:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");

Carbide answered 27/11, 2017 at 14:46 Comment(1)
"ZZZZZ" doesn't help you much if you get a String with "-08:00".Clishmaclaver
H
1

In case somebody will look here for an answer how to format string with pattern "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" for devices with API lower than 24.

Use Java DateTimeFormatter and OffsetDateTime since it does not require providing input pattern like SimpleDateFormat

Java code :

 public static String formatISO8601String(String string) {
        DateTimeFormatter desiredFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        OffsetDateTime dateTime = OffsetDateTime.parse(string);
        return dateTime.format(desiredFormat);
    }

Kotlin code :

fun formatISO8601String(string: String): String {
        val desiredFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
        val dateTime = OffsetDateTime.parse(string)
        return dateTime.format(desiredFormat)
    }
Hygrograph answered 21/12, 2021 at 17:29 Comment(0)
B
0

The pattern you need is "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" and yet it mentions a lowercase x in the exception. Looks like you have a typo somewhere.

Bezel answered 16/6, 2017 at 11:48 Comment(4)
i tried both upper and lowercase, ill edit question to clarifyEmbus
also, on the examples they show on documentation they have "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" 2001-07-04T12:08:56.235-07:00Embus
You need to use UPPERCASE absolutely. Like I am mentioning. What is the exception when you use the UPPERCASE X?Bezel
java.lang.IllegalArgumentException: Unknown pattern character 'X'Embus
C
-1

i think you are looking for "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

Change date format 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");

this may be help you

Cafard answered 16/6, 2017 at 11:46 Comment(5)
Z is RFC-style time zone, while another one is ISO-style time zone. I don't think these'll work in general (they might for some special cases).Obligation
you can refer developer.android.com/reference/java/text/SimpleDateFormat.htmlCafard
where small z used for general time zoneCafard
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.UK); String formattedDate = sdf.format(new Date());Cafard
And this format could parse "2001-07-04T12:08:56.235-07:00"? (Can't try at the moment)?Clishmaclaver

© 2022 - 2024 — McMap. All rights reserved.