Illegal pattern character 'T' when parsing a date string to java.util.Date
Update for Java 8 and higher
You can now simply do Instant.parse("2015-04-28T14:23:38.521Z")
and get the correct thing now, especially since you should be using Instant
instead of the broken java.util.Date
with the most recent versions of Java.
You should be using DateTimeFormatter
instead of SimpleDateFormatter
as well.
Original Answer:
The explanation below is still valid as as what the format represents.
But it was written before Java 8 was ubiquitous so it uses the old
classes that you should not be using if you are using Java 8 or
higher.
This works with the input with the trailing Z
as demonstrated:
In the pattern the
T
is escaped with'
on either side.The pattern for the
Z
at the end is actuallyXXX
as documented
in the JavaDoc forSimpleDateFormat
, it is just not very clear
on actually how to use it sinceZ
is the marker for the old
TimeZone
information as well.
Q2597083.java
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class Q2597083
{
/**
* All Dates are normalized to UTC, it is up the client code to convert to the appropriate TimeZone.
*/
public static final TimeZone UTC;
/**
* @see <a href="http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations">Combined Date and Time Representations</a>
*/
public static final String ISO_8601_24H_FULL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
/**
* 0001-01-01T00:00:00.000Z
*/
public static final Date BEGINNING_OF_TIME;
/**
* 292278994-08-17T07:12:55.807Z
*/
public static final Date END_OF_TIME;
static
{
UTC = TimeZone.getTimeZone("UTC");
TimeZone.setDefault(UTC);
final Calendar c = new GregorianCalendar(UTC);
c.set(1, 0, 1, 0, 0, 0);
c.set(Calendar.MILLISECOND, 0);
BEGINNING_OF_TIME = c.getTime();
c.setTime(new Date(Long.MAX_VALUE));
END_OF_TIME = c.getTime();
}
public static void main(String[] args) throws Exception
{
final SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_24H_FULL_FORMAT);
sdf.setTimeZone(UTC);
System.out.println("sdf.format(BEGINNING_OF_TIME) = " + sdf.format(BEGINNING_OF_TIME));
System.out.println("sdf.format(END_OF_TIME) = " + sdf.format(END_OF_TIME));
System.out.println("sdf.format(new Date()) = " + sdf.format(new Date()));
System.out.println("sdf.parse(\"2015-04-28T14:23:38.521Z\") = " + sdf.parse("2015-04-28T14:23:38.521Z"));
System.out.println("sdf.parse(\"0001-01-01T00:00:00.000Z\") = " + sdf.parse("0001-01-01T00:00:00.000Z"));
System.out.println("sdf.parse(\"292278994-08-17T07:12:55.807Z\") = " + sdf.parse("292278994-08-17T07:12:55.807Z"));
}
}
Produces the following output:
sdf.format(BEGINNING_OF_TIME) = 0001-01-01T00:00:00.000Z
sdf.format(END_OF_TIME) = 292278994-08-17T07:12:55.807Z
sdf.format(new Date()) = 2015-04-28T14:38:25.956Z
sdf.parse("2015-04-28T14:23:38.521Z") = Tue Apr 28 14:23:38 UTC 2015
sdf.parse("0001-01-01T00:00:00.000Z") = Sat Jan 01 00:00:00 UTC 1
sdf.parse("292278994-08-17T07:12:55.807Z") = Sun Aug 17 07:12:55 UTC 292278994
Parsing string to date: Illegal pattern character 'T'.
Given your input of 2014-09-17T12:00:44.0000000Z
, it is not sufficient to escape the letter T
only. You also have to handle the trailing Z
. But be aware, this Z
is NOT a literal, but has the meaning of UTC+00:00
timezone offset according to ISO-8601-standard
. So escaping Z
is NOT correct.
SimpleDateFormat
handles this special char Z
by pattern symbol X
. So the final solution looks like:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX");
Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
System.out.println(d); // output: Wed Sep 17 14:00:44 CEST 2014
Note that the different clock time is right for timezone CEST
(toString()
uses system timezone), and that the result is equivalent to UTC-time 12:00:44
. Furthermore, I had to insert seven symbols S in order to correctly process your input which pretends to have precision down to 100ns
(although Java pre 8 can only process milliseconds).
getting java.lang.IllegalArgumentException: Illegal pattern character 'o'? while parsing java.text.SimpleDateFormat
Try this instead:
DateFormat formatter = new SimpleDateFormat("EEE MMM dd hh:mm:ss zzz yyyy");
E
is used for "Day in Week" as text, M
is the month name.
SimpleDateFormat Illegal pattern character error with localized pattern
Unfortunately the documentation of how to handle localized patterns is horrible. So I studied the source code and made my own investigations. Result:
The constructor of SimpleDateFormat
accepting a pattern string only refers to the unlocalized pattern characters whose definition is documented as given in the javadoc header of class SimpleDateFormat
. These unlocalized pattern characters are also defined as constant in DateTimeFormatSymbols
:
/**
* Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
* All locales use the same these unlocalized pattern characters.
*/
static final String patternChars = "GyMdkHmsSEDFwWahKzZYuXL";
Three steps are necessary in order to use localized patterns (like "tt.MM.uuuu" what you believe to be German - but is NOT German, it should rather be "TT.MM.JJJJ" - example for wrong JDK resources):
- Define the localized pattern characters via
DateFormatSymbols.setLocalPatternChars(...)
. - Use the customized date-format-symbols on your
SimpleDateFormat
-object. - Apply the localized date-time-pattern via
SimpleDateFormat.applyLocalizedPattern(...)
Then the localized pattern will be translated to the internal and official pattern character definition.
Example of usage (using the correct German pattern TT.MM.JJJJ):
SimpleDateFormat sdf = new SimpleDateFormat(); // uses default locale (here for Germany)
System.out.println(sdf.toPattern()); // dd.MM.yy HH:mm
System.out.println(sdf.toLocalizedPattern()); // tt.MM.uu HH:mm
DateFormatSymbols dfs = DateFormatSymbols.getInstance(Locale.GERMANY);
dfs.setLocalPatternChars("GJMTkHmsSEDFwWahKzZYuXL");
sdf.setDateFormatSymbols(dfs);
sdf.applyLocalizedPattern("TT.MM.JJJJ");
System.out.println(sdf.toPattern()); // dd.MM.yyyy
System.out.println(sdf.toLocalizedPattern()); // TT.MM.JJJJ
System.out.println(sdf.format(new Date())); // 20.06.2016
Side note: I have changed the appropriate pattern chars y and d to J and T in the string "GyMdkHmsSEDFwWahKzZYuXL" to make a localized definition.
Unfortunately the JDK resources are obviously not reliable so my personal view is that the whole feature can only be used in an awkward way and is not very useful in practice.
Groovy Date Parsing -- X is an illegal pattern character
The simplest answer I can think of, is just to use 'Z'. The issue here is that -04:00 isn't recognised by the parser. So why not just run a regex prior to trying to convert it, looking for the final : and removing it.
How to check time SImpleDateFormat?
You probably want String#matches
here with an appropriate regex pattern:
String dt = "2020-11-23T21:17:03.039023Z";
String regex = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{6}Z";
if (dt.matches(regex)) {
Log.e("TAG", "true");
}
else {
Log.e("TAG", "false");
}
But note that the above does not actually do any validation on the input, but rather just detects the general pattern, and distinguishes from the version with no millisecond/microsecond precision.
Java SimpleDateFormat can not parse date in yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX format pattern
Use java.time
:
You can parse this example String
without any explicit pattern, keep the precision as desired and, if necessary, format those date and time values in a multitude of custom ways.
Here's a small example:
public static void main(String[] args) {
// example String (of ISO format)
String input = "2021-06-28T07:09:30.463931900Z";
// parse it (using a standard format implicitly)
OffsetDateTime odt = OffsetDateTime.parse(input);
// print the result
System.out.println(odt);
// if you want a different output, define a formatter
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(
// use a desired pattern
"EEE MMM dd HH:mm:ss O uuuu",
// and a desired locale (important for names)
Locale.ENGLISH);
// print that
System.out.println(odt.format(dtf));
}
This code example produces the following output:
2021-06-28T07:09:30.463931900Z
Mon Jun 28 07:09:30 GMT 2021
Related Topics
Java 7 Language Features with Android
How to Return an Array from Jni to Java
Using Static Variables in Android
Differencebetween List and Arraylist
Custom Listview Click Issue on Items in Android
Android: How to Get the Current Day of the Week (Monday, etc...) in the User's Language
How Delete a Collection or Subcollection from Firestore
Foreign Key Constraints in Android Using SQLite? on Delete Cascade
Service Discovery Failed Exception Using Bluetooth on Android
Sqlite in Android How to Update a Specific Row
Understand the R Class in Android
Eclipse 3.6 Helios for Ubuntu 10.10
How to Create a Linux Cluster for Running Physics Simulations in Java
Connect as User with No Password Set on Postgresql 8.4 via Jdbc
Could Not Create the Java Virtual MAChine
Windows: Moving a File That Was Previously Mapped in Memory Fails