java.lang.IllegalArgumentException: Parse error: Unable to parse Date format - java

I need to format following date fomat
timeBooked: "2015-05-20T02:08:00.000Z",
ExpiryTime: "2015-05-20T04:08:00.000Z",
My code follows to format the date:
try {
Date currentDate = new Date(timeBooked);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.ZZ", Locale.ENGLISH);
Log.e(TAG, "formatted time string: " + sdf.format(currentDate.getTime()));
Log.e(TAG, "date string:=" + currentDate.getDate());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
While running this code getting java.lang.IllegalArgumentException: Parse error:2015-05-20T02:08:00.000Z.

Your format String is incorrect. It should be "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'".
Then to get your date correctly you should use:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
// Set time zone to UTC since 'Z' at end of String specifies it.
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
// The parsed date will be offset from UTC in device's current TimeZone.
Date currentDate = sdf.parse(timeBooked);

The Date constructor taking a string is deprecated: see http://developer.android.com/reference/java/util/Date.html#Date(java.lang.String). It won't accept a custom date format; only a pre-defined set of formats are allowed.
Once you get your DateFormat string correct (I think "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" should work) you can call sdf.parse(timeBooked) to get a valid Date.

Z Has Meaning
Both of the previous Answers tell you to expect-and-ignore the Z character, by surrounding with single quotes in the coded parsing pattern. Bad advice. You would be ignoring valuable data, and would be rejecting valid alternative inputs such as 2015-05-20T02:08:00.000+05:30. The pattern code Z means "any valid offset-from-UTC". Adding the single quotes for 'Z' says "expect an uppercase Z to appear here, ignore any meaning it may have, and throw an exception if the Z is missing".
Joda-Time
You are using the old date-time classes bundled with early versions of Java. Those classes have proven to be troublesome, flawed in both design and implementation. Avoid them. In current Android, add the Joda-Time library to your project. In Java 8 and later, use the java.time framework that was inspired by Joda-Time.
Your string inputs are in ISO 8601 standard format. Both Joda-Time and java.time use ISO 8601 as their defaults when parsing/generating textual representations of date-time values. So you these classes can directly parse such strings without you needing to specify any coded parsing patterns.
The following code creates a date-time assigned an offset-from-UTC of 0, which is what the Z (for Zulu) means.
DateTime dateTime = DateTime.parse( "2015-05-20T02:08:00.000Z" );
Using a constructor has a different meaning. The following code parses the value with an offset of zero but then adjusts the results into your JVM’s current default time zone.
DateTime dateTime = new DateTime( "2015-05-20T02:08:00.000Z" ) );
I suggest you always explicitly assign your desired/expected time zone.
DateTimeZone zone = DateTimezone.forID( "Europe/Paris" );
DateTime dateTime_Europe_Paris = dateTime.withZone( zone );
If you really need a java.util.Date, convert after doing your parsing and business logic with Joda-Time.
java.util.Date date = dateTime.toDate();
Search StackOverflow for many more Questions and Answers with example code for Joda-Time.

Related

Kotlin date parsing is not working properly

So I have been looking up on how to properly parse an incoming datetime, problem is that this string contains the zone as well which apparently can't be parsed for some reason.
To give an example of the incoming date time string:
2021-10-05T10:00:00.0000000
Now I tried to the following:
var dateTimeString = "2021-10-05T10:00:00.0000000"
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
var date = LocalDate.parse(dateTimeString, formatter)
I tried replacing Z with nothing and with ZZZZ, but that didn't work I assume it doesn't work because of the plus or minus sign not being present. FYI, I receive the date in this format because of the Microsoft Graph API when retrieving the calendar events.
Any idea as to how this date should be formatted properly?
Edit: This comes from Microsoft Graph. Basically they give like a date as an object:
"start": {
"dateTime": "2021-10-05T10:00:00.0000000",
"timeZone": "UTC"
}
This is the page of the documentation that explains this date object: dateTimeTimeZone resource type.
Update:
I was finally able to solve this date issue, what I did was the following:
var inputDateTime = "2021-10-05T10:00:00.0000000"
var inputTimeZone = "UTC"
var zonedDateTime = ZonedDateTime.parse(
inputDateTime,
DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.of(inputTimeZone))
).withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime()
This way, the date would be converted correctly to the right time zone and to the right Date/Time.
As I can see from docs you've provided https://learn.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0
dateTime String A single point of time in a combined date and time representation ({date}T{time}; for example, 2017-08-29T04:00:00.0000000).
timeZone String Represents a time zone, for example, "Pacific Standard Time". See below for more possible values.
dateTime object has no zone encoded. And all 7 zeroes represent fractions of a second. In such case it's regular ISO_DATE_TIME and you don't need to create your own formatter.
The following code should work
var dateTimeString = "2021-10-05T10:00:00.0000000"
var date = LocalDate.parse(dateTimeString, DateTimeFormatter.ISO_DATE_TIME)
Your Date-Time string does not have timezone information
Your Date-Time string, 2021-10-05T10:00:00.0000000 does not have timezone information. The .0000000 represents the fraction of a second and as of now, java.time is capable of handling up to 9 digits of precision (i.e. nanosecond of precision).
Since it does not have timezone information, it represents a local Date-Time and hence should be parsed into LocalDateTime.
You do not need a DateTimeFormatter for your Date-Time string
The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards. Your Date-Time string is already in the ISO 8601 format.
Demo:
import java.time.LocalDateTime;
public class Main {
public static void main(String args[]) {
var dateTimeString = "2021-10-05T10:00:00.0000000";
var ldt = LocalDateTime.parse(dateTimeString);
System.out.println(ldt);
}
}
Output:
2021-10-05T10:00
ONLINE DEMO
How to get ZonedDateTime out of the LocalDateTime instance?
You can use LocalDateTime#atZone to convert attach a ZoneId to a LocalDateTime resulting into a ZonedDateTime.
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Etc/UTC"));
Note: If you need an Instant, you can get it from this instant of ZonedDateTime e.g.
Instant instant = zdt.toInstant();
An Instant represents an instantaneous point on the timeline, normally represented in UTC time. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time.
For the case that the last 4 digits in your example String are not representing a time zone:
Parse it without a formatter (no need since it would be perfect ISO standard if the last 4 digits are just additional fractions of second), but also consider the time zone you get with the JSON:
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
fun main() {
// the time String from JSON
var dateTimeString = "2021-10-05T10:00:00.0000000"
// the zone from JSON (may not always work, but does with UTC)
var timeZone = "UTC"
// create the zone from the timezone String
var zoneId = ZoneId.of(timeZone)
// then parse the time String using plain LocalDateTime and add the zone afterwards
var zdt: ZonedDateTime = LocalDateTime.parse(dateTimeString).atZone(zoneId)
// print some results
println("Full ZonedDateTime: ${zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)}")
println("(Local)Date only: ${zdt.toLocalDate()}")
}
Full ZonedDateTime: 2021-10-05T10:00:00Z[UTC]
(Local)Date only: 2021-10-05
Please note that parsing the time zones currently supported by Windows won't work this easy (except from UTC), but the time zones supported by the calendar API are (mostly) sufficient for the creation of a java.time.ZoneId.
As a supplement: Your documentation mentions Pacific Standard Time as a time zone string that may come as part of your MS Graph dateTimeTimeZone. I don’t think the other answers can handle that one, so I should like to show how you do handle it in Java.
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzzz", Locale.ENGLISH);
static ZoneId parseZone(String timeZoneString) {
try {
return ZoneId.from(ZONE_FORMATTER.parse(timeZoneString));
} catch (DateTimeParseException dtpe) {
return ZoneId.of(timeZoneString);
}
}
I believe that this handles the strings mentioned in the documentation and also UTC from your question. I am demonstrating just three different ones:
String[] msTimeZoneStrings = { "UTC", "Pacific Standard Time", "Pacific/Honolulu" };
for (String zoneString : msTimeZoneStrings) {
ZoneId zid = parseZone(zoneString);
System.out.format("%-21s parsed to %s%n", zoneString, zid);
}
Output:
UTC parsed to UTC
Pacific Standard Time parsed to America/Los_Angeles
Pacific/Honolulu parsed to Pacific/Honolulu
In the formatter I use zzzz is for time zone name like Pacific Standard Time. My parse method tries this formatter first. It fails for UTC and Pacific/Honolulu. When the DateTimeParseException is caught, the method next tries the ZoneId.of method also used in the other answers. It handles UTC and all the time zone ID sin region/city format mentioned in the documentation.
Combine the ZoneId obtained from my method with the parsed LocalDateTime to get a ZonedDateTime the way that deHaar is already showing in their answer.

Date conversion from yyyy-MM-dd HH:mm:ss to ISO date yyyy-MM-dd'T'HH:mm:ssXXX format issue

I'm trying to convert date format from yyyy-MM-dd HH:mm:ss to ISO date format yyyy-MM-dd'T'HH:mm:ss+5:30, and tested it by below code and it was working fine when ran on eclipse and causing an issue on deployment to server through jar.
The issue is date(input: 2016-01-08 10:22:03) is converted to something like, 2016-01-08T10:22:03Z instead of 2016-01-08T10:22:03+5:30.
Note: I'm using Java 8.
Following is the code used to convert the date,
SimpleDateFormat outputDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
SimpleDateFormat inputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String FinalDate = outputDate.format(inputDate.parse(pickupDate));
System.out.println(finalDate);
Other weird experience is, on some machine the issue is not reproducible and in some machine the issue exists. Is it something machine or JVM dependent? Please help.
Thank you in advance.
As by documentation of SimpleDateFormat:
For formatting, if the offset value from GMT is 0, "Z" is produced. If
the number of pattern letters is 1, any fraction of an hour is
ignored. For example, if the pattern is "X" and the time zone is
"GMT+05:30", "+05" is produced.
So my guess is probably to check the timezone of your server. Since it thinks that the timezone of the entered date is GMT 0.
java.time
If using Java 8 or later, you should be using the java.time classes rather than those notoriously troublesome date-time classes, java.util.Date/.Calendar.
ISO 8601
Your input strings are close to the standard ISO 8601 format. The java.time classes use these standard formats by default when parsing and generating textual representations of date-time values. No need to define a coded parsing pattern for such standard inputs.
To fully comply with ISO 8601, replace that SPACE in the middle with a T.
String inputStandardized = "2016-01-08 10:22:03".replace( " " , "T" );
Parsing Without Time Zone Or Offset
This string has no offset-from-UTC or time zone, so we first create a LocalDateTime.
LocalDateTime localDateTime = LocalDateTime.parse( inputStandardized );
Such objects are a vague idea of a date-time but are not really on the timeline. To define a real moment on the timeline we must apply a time zone.
ZoneId zoneId = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = localDateTime.atZone( zoneId );
Apply Time Zone
Note that that particular date + time may not be valid in the specified time zone; java.time adjusts as necessary. Be sure to read the documentation to understand the adjustment behavior.
Formatted Strings
The toString method on ZonedDateTime by default generates a String in the format you desire, except extended to append the name of the time zone in square brackets.
String output = zdt.toString();
2016-01-08T10:22:03+05:30[Asia/Kolkata]
This extension to include time zone name makes much sense. A time zone is not just an offset-from-UTC, it also includes the present and historical rules for handling anomalies such as Daylight Saving Time (DST).
If you really do not want that appended time zone name, against my advice, you can use an alternate formatting pattern, ISO_OFFSET_DATE_TIME, already defined in java.time as a constant.
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME ;
String output = zdt.format( formatter );
2016-01-08T10:22:03+05:30
Pad Hour Of Offset
By the way, you can avoid problems by always including a leading padding zero in the hours of your offset-from-UTC. So use +05:30 rather than +5:30 as seen in the Question.

How to convert a date and time in one time zone to other in java

I am trying to convert GMT+2 time to GMT-4 time.But i am getting unexpected results.Help me on how to achieve that conversion of one time zone time to other time zone time.
originTime = "2015-08-15T10:25:00";
SimpleDateFormat converter = new SimpleDateFormat("yyyy-MM-dd hh:mm");
converter.setTimeZone(TimeZone.getTimeZone("GMT-4"));
GregorianCalendar oc = originTime.toGregorianCalendar();
String OriginStart=converter.format(oc.getTime());
The above code has to give the originStart time lesser than the given time If it is GMT-4.
But Im getting OriginStart time greater than the given time.
Assuming the timzone strings are valid (as i haven't tried it) try something like
String originTime = "2015-08-15 10:25";
SimpleDateFormat converter = new SimpleDateFormat("yyyy-MM-dd hh:mm");
converter.setTimeZone(TimeZone.getTimeZone("GMT+10"));
Date date = converter.parse (originTime);
converter.setTimeZone(TimeZone.getTimeZone("GMT-4"));
String OriginStart=converter.format(date);
Padding Zero
Generally, use a padding zero for offset hours. But this is not a problem in your specific code. At least not according to the doc for TimeZone class which explicitly accepts single digit.
The ISO 8601 standard requires offset hours to have a padding zero. So use -04 rather than -4.
By the way, the original release of java.time had a bug where it failed to parse offsets values of just hour without menu. So in that case, use -04:00 rather than -04.
Named Time Zone
A time zone is more that just an offset from UTC (GMT). A time zone includes rules about Daylight Savings Time (DST) and other anomalies, past, present, and future. So use a specific time zone name if you have one in mind.
An example of a +02:00 time zone name would be Africa/Bujumbura. An example of -04:00, America/Martinique.
Avoid java.util.Date
The java.util.Date/.Calendar and SimpleDateFormat classes are notoriously troublesome and confusing. Perhaps the worst of the bundled Java libraries. Avoid them.
Instead use either Joda-Time or the new java.time package built into Java 8 (inspired by Joda-Time).
ISO 8601
The ISO 8601 standard defines sensible unambiguous string formats for date-time values. Your input string format complies with this wise standard.
Both Joda-Time and java.time parse and generate strings in ISO 8601 format by default. So no need to specify a formatter.
Example
Example code written in Joda-Time 2.7.
Define the input, formatted in ISO 8601 without any offset from UTC.
String input = "2015-08-15T10:25:00";
Specify time zones if input and output.
DateTimeZone zoneInput = DateTimeZone.forOffsetHours( 2 );
// DateTimeZone zoneInput = DateTimeZone.forID( "Africa/Bujumbura" ); // Preferably the specific time zone name.
DateTimeZone zoneTarget = DateTimeZone.forOffsetHours( -4 );
// DateTimeZone zoneTarget = DateTimeZone.forID( "America/Martinique" ); // Preferably the specific time zone name.
Parse the string, while assigning a time zone. Then adjust the time zone.
DateTime dateTimeOriginal = new DateTime( input , zoneInput );
DateTime dateTimeTarget = dateTimeOriginal.withZone( zoneTarget );
Dump to console.
System.out.println( "zoneInput / zoneTarget : " + zoneInput + " / " + zoneTarget );
System.out.println( "dateTimeOriginal : " + dateTimeOriginal );
System.out.println( "dateTimeTarget : " + dateTimeTarget );
When run.
zoneInput / zoneTarget : +02:00 / -04:00
dateTimeOriginal : 2015-08-15T10:25:00.000+02:00
dateTimeTarget : 2015-08-15T04:25:00.000-04:00

is there a simple way to convert Date(sql) to following format Month(3 character) day(int) , year(2014)

is there a simple way to convert Date(sql) to following format Month(3 character) day(int) , year(int)?
For example:
Jan 3, 2014
Feb 2, 2014
I have this: "2014-02-14"
(i use postgresql, java and javascript on client)
Assuming , if you want to achieve this in the Database side itself. Then use the below sql query.
Lets say "stack" is the column containing your DATE value ie "2014-02-14"
select to_char(stack,'Mon dd, YYYY') from testing;
to_char
--
Feb 14, 2014
Take a look at Java's SimpleDateFormat API
You can do something like this --
SimpleDateFormat format = new SimpleDateFormat("MMM dd, YYYY");
String dateString = format.format(date); // Pass your SQL date object here
This will work:
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy");
SimpleDateFormat sqlformat = new SimpleDateFormat("yyyy-mm-dd");
java.util.Date date;
try {
date = sqlformat.parse("2014-02-14");
String result = format.format(date);
System.out.println(result);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // Pass your SQL date object here
Short Answer
In Joda-Time 2.3 (substitute your desired time zone and Locale)…
String output = DateTimeFormat.forStyle( "M-" ).withLocale( new java.util.Locale( "fr", "CA" ).withTimeZone( "America/Montreal").print( new DateTime( myJavaDotSqlDotJavaObject ) );
A Date-Time Object Has No Format
You are making the common mistake of conflating a date-time value with its string representation. A java.sql.Date object has no String format. You can generate a String representation from a date-time object, but the two are separate independent objects.
ISO 8601
The format you mentioned is defined by the ISO 8601 standard. The Joda-Time date-time library uses ISO 8601 for its defaults for both inputs and outputs.
Time Zone
Both the question and other answers ignore the crucial issue of time zone.
Determining what day it is (yesterday, today, tomorrow) depends on your time zone. While a new day dawns in Paris for Feb 2, in Montréal the date is still Feb 1.
A java.sql.Date instance has no time zone. It's date-time value internally is effectively in UTC (no offset).
Decent Date-Time Library
The bundled java.util.Date and .Calendar classes in Java are notoriously troublesome. Avoid them. Use either:
Joda-Time
The new java.time package in Java 8.
Joda-Time
Some example code in Joda-Time 2.3.
Get the current date-time.
DateTimeZone timeZoneParis = DateTimeZone.forID( "Europe/Paris" );
DateTime nowInParis = DateTime.now( timeZone );
To convert your java.sql.Date instance to a Joda-Time object, simply pass it to the constructor. Be sure to include a time zone to be assigned to the Joda-Time DateTime object. If you omit the time zone, the JVM’s default zone is assigned.
DateTime dateTimeInParis = new DateTime( myJavaDotSqlDotDateObject, timeZoneParis );
Adjust for time zone.
DateTimeZone timeZoneMontréal = DateTimeZone.forID( "America/Montreal" );
DateTime nowInMontréal = nowInParis.withTimeZone( timeZone );
You may adjust to UTC. This might be helpful for debugging, to verify the UTC value stored in your database. Postgres always stores TIMESTAMP types in UTC. I repeat: both TIMESTAMP WITH TIME ZONE and TIMESTAMP WITHOUT TIME ZONE types are stored in UTC. The 'with' or 'without' names are misleading, as they refer not to storage but to whether or not a time zone is respected during insertion into or retrieval from the database. Expert advice says: Always use TIMESTAMP WITH TIME ZONE.
DateTime dateTimeInUtc = nowInMontréal.withTimeZone( DateTimeZone.UTC );
Generate a string representation of the date-time value using one of the built-in ISO 8601 formatters. For the date-only YYYY-MM-DD format you mentioned, call the factory method ISODateTimeFormat.date().
For the MMM DD, YYYY format you want, I suggest you instead use a localized format. See the line of code at the top of this answer for an example. Pass "M-" to generate a medium-length string representation of the date portion while omitting the time portion. Pass "F", "L", "M", or "S" for Full, Long, Medium, and Short.
If you insist on exactly your specified format, you may create a formatter using the DateTimeFormat.forPattern method. Search StackOverflow for many examples.
Note that the formatter can do the time zone adjusting as part of its process, as an alternative to the time zone adjustment we saw above. The formatter can also localize.
DateTimeFormat formatter = ISODateTimeFormat.date().withTimeZone( timeZoneMontréal ).withLocale( new java.util.Locale( "fr", "CA" ); // Factory producing formatters.
String outputDateOnlyInMontréal = formatter.print( nowInParis );

Java unparseable date

There is the following code:
Date st = new SimpleDateFormat("HH:mm").parse(date);
And I get the following exception "Unparseable date: "2000-01-01T01:00:00Z" (at offset 4)". How can I fix it?
tl;dr
Instant.parse( "2000-01-01T01:00:00Z" )
Wrong Parsing Pattern
You defined a formatting pattern that says you expect the input string to be hours and minutes. But your input string has much more, years, months, and so on.
java.time
As of Java 8 and later, the old java.util.Date/.Calendar and java.text.SimpleDateFormat have been supplanted by the new java.time package. Avoid the old classes whenever possible as they have proven to be confusing, troublesome, and flawed.
Your input string is using one of the standard date-time formats defined by ISO 8601. Fortunately, java.time uses that format by default.
String input = "2000-01-01T01:00:00Z" ;
Instant instant = Instant.parse( input ) ;
An Instant is a moment on the timeline basically in UTC. You may adjust the value to a particular time zone (a ZoneId), producing a ZonedDateTime object.
ZonedId zoneId = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( instant , zoneId ) ;
If you call toString on a ZonedDateTime, you will get a string like:
1999-12-31T20:00:00-05:00[America/Montreal]
The ZonedDateTime class extends the ISO 8601 format by appending the name of the time zone in brackets.
Date st = new SimpleDateFormat("HH:mm").parse(date.substring(11,16));
Use this format instead:
Date st = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(date);
SimpleDateFormat is very unforgiving. It expects you to pass a String that exactly matches the format string you initialized it with. If you pass "HH:mm" as its format string, it will not be able to handle any other format - it cannot handle a date with a year in it, etc. It will handle "3:56" (in which case you'll get Jan 1, 1970 at 03:56AM in your Date).
SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
Date date = dtf.parse(date);
dtf = new SimpleDateFormat("HH:mm");
String dateStr = dtf.format(date);
Date finalDate = dtf.parse(date);
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
The date in the exception is an xml schema dateTime. Note that simply creating
SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Will not work entirely as you might think because the Z indicates "UTC" timezone and the parser is by default initialized as local time.
Also note that the schema dateTime has a variable definition, it can (optionally) have millisecond precision (0 or more milliseconds) and the timezone (if something other than Z) is not compatible with the format of SimpleDateFormat.
In short: xml date times are tricky with the default libraries. I have written a custom solution for handling them in our environment but you could also look at the joda time library which I believe handles them well. Or you could wait for the next java version which will have a new date API.

Categories

Resources