Unparsable Date despite perfect format - java

I'm trying to parse a date departureTime:
String departureTime2, departureTime;
departureTime2 = departureTime = "2018-01-01 11:11:11.1";
Using the JUnit when method
when(bookingController.booking( departureTime, departureTime2).thenAnswer(new Answer<MockHttpSession>()
{
#Override
public MockHttpSession answer(InvocationOnMock invocation) throws Throwable
{
Object[] args = invocation.getArguments();
return (MockHttpSession) args[0];
}
});
My booking method in BookingController
#RequestMapping(value = "/bookingsingle", method = RequestMethod.POST)
public String bookingSingle(#RequestParam String departureTime,..)'
formats the date using
Date departureTimeAsDate = null;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.S", Locale.ENGLISH);
try { departureTimeAsDate = df.parse(departureTime); } catch (ParseException e) { e.printStackTrace(); }
However I receive the error
java.text.ParseException: Unparseable date: "2018-01-01 11:11:11.1"
The date appears to be in the perfect format, and upon using the same code in a Java fiddle tool it compiles, however in intellij it runs into the error. Any suggestions would be appreciated.
EDIT:
I believe the problem may lie somewhere in the passing of the String in the when() method. Note that booking() has many irrelevant parameters I have excluded.

Related

After set the location, timezone can't convert

Below is my coding:
private final String TIME_ZONE_ID_TRKD_DEFAULT = "Etc/GMT";
private XMLGregorianCalendar getStartDateTime(boolean startFromZeroHour) {
XMLGregorianCalendar xmlCal = null;
try {
xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar();
} catch (DatatypeConfigurationException e) {
e.printStackTrace();
}
Calendar now = Calendar.getInstance(TimeZone.getTimeZone("Asia/Singapore"));
now.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_ID_TRKD_DEFAULT));
xmlCal.setDay(now.get(Calendar.DAY_OF_MONTH));
xmlCal.setMonth(now.get(Calendar.MONTH) + 1);
xmlCal.setYear(now.get(Calendar.YEAR));
xmlCal.setTime(now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
please kindly advice why it can't convert, and how should i do..
The code cannot be compiled because of an error on the line, where you get the instance of the calendar. I believe you wanted to do this (probably just copy/paste error?):
Calendar now = Calendar.getInstance(TimeZone.getTimeZone("Asia/Singapore"));
A better approach might be the following:
private final String TIME_ZONE_ID_TRKD_DEFAULT = "Etc/GMT";
private XMLGregorianCalendar getStartDateTime(boolean startFromZeroHour) {
XMLGregorianCalendar xmlCal = null;
try {
xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar(TimeZone.getTimeZone(TIME_ZONE_ID_TRKD_DEFAULT)));
} catch (DatatypeConfigurationException e) {
e.printStackTrace();
}
xmlCal.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
xmlCal.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
if(startFromZeroHour){
xmlCal.setHour(0);
}
return xmlCal;
}
public static void main(String[] args) {
Bug b = new Bug();
XMLGregorianCalendar startDateTime = b.getStartDateTime(true);
System.out.println(startDateTime);
XMLGregorianCalendar startDateTime2 = b.getStartDateTime(false);
System.out.println(startDateTime2);
}
First we create a GregorianCalendar instance using your timezone constant. It represents the current time (now) if the default constructor is used.
Then we use it to initialize the XMLGregorianCalendar.
You don't want to have the milliseconds and the timezone part, so we just unset them using DatatypeConstants.FIELD_UNDEFINED as stated in the JavaDoc https://docs.oracle.com/javase/7/docs/api/javax/xml/datatype/XMLGregorianCalendar.html#setMillisecond(int) .
I added a part setting the hour to zero if startFromZeroHour is set to true. It was not part of your code so you might want to remove or change it.

Parsing Json Dates with varying standards

I'm reading JSON data from an API using Jackson and most of the time I get an array of objects that are all fairly standard in their implementation. The only issue is that sometimes dates will be in the format "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" and sometimes in the format "yyyy-MM-dd", so the JSON looks like this:
[
{
'A':'Foo'
'B':'2016-11-03T12:35:23.032Z'
'C':'7'
},
{
'A':'Bar'
'B':'2016-11-06'
'C':'4'
},
{
'A':'Bla'
'B':'2016-11-07T14:42:18.832Z'
'C':'23'
},
{
'A':'Blo'
'B':'2016-11-07T15:12:23.439Z'
'C':'9'
}
]
Every time I get to that second date I get a parser error because it's not in the same format. I tried writing a class that will use a second DateFormat if the first one fails, but now I just get a NullPointerException.
public class BackupDateFormat extends DateFormat {
private final LinkedList<DateFormat> formats;
public BackupDateFormat(DateFormat... dfs) {
formats = new LinkedList<>(Arrays.asList(dfs));
}
#Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return formats.getFirst().format(date, toAppendTo, fieldPosition);
}
#Override
public Date parse(String source, ParsePosition pos) {
return formats.getFirst().parse(source, pos);
}
#Override
public Date parse(String source) throws ParseException {
ParseException exception = null;
for (DateFormat df : formats) {
try {
return df.parse(source);
}
catch (ParseException pe) {
exception = pe;
}
}
throw exception;
}
}
His is the error I'm getting:
com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.company.api.API$Result["result"]->java.util.ArrayList[0]->com.company.models.othercompany.Record["dateTime"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1597)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:294)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:266)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:485)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:108)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3836)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2860)
at com.mentoredata.api.API.get(API.java:56)
This is the code at line 56:
return mapper.<List<T>>readValue(new URL(url), mapper.getTypeFactory().constructCollectionType(List.class, type));
Does anyone know how I can either fix my current code to not get a null pointer or use two dateformats in Jackson?
I'm having trouble telling exactly what your problem is, but I was able to get things working with the code you have. First, I created a POJO representing the object you are trying to deserialize. I'm kind of assuming you already have an equivalent, but this was mine:
class Obj {
String A;
Date B;
Integer C;
/* with getters/setters */
}
Then, I created a custom deserializer with the object mapper. The class is not too difficult to implement. I used your BackupDateFormat inside of the deserializer:
class ObjDeserializer extends JsonDeserializer<Obj> {
final BackupDateFormat backupDateFormat;
public ObjDeserializer() {
backupDateFormat = new BackupDateFormat(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
new SimpleDateFormat("yyyy-MM-dd"));
}
#Override
public Obj deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
// create a POJO and populate with the fields from the JSON Object
Obj obj = new Obj();
JsonNode root = p.readValueAsTree();
obj.setA(root.get("A").asText(""));
obj.setC(root.get("C").asInt(0));
try {
obj.setB(backupDateFormat.parse(root.get("B").asText()));
} catch (ParseException e) {
throw new IOException("Could not parse date as expected.");
}
return obj;
}
}
After that, register your serializer with the ObjectMapper:
SimpleModule dateDeserializerModule = new SimpleModule();
// associate the custom deserializer with your POJO
dateDeserializerModule.addDeserializer(Obj.class, new ObjDeserializer());
mapper.registerModule(dateDeserializerModule);
Finally, you can see that the dates were appropriately parsed from this snippet and its output:
List<Obj> result = mapper.readValue(input.getBytes(), mapper.getTypeFactory().constructCollectionType(List.class, Obj.class));
result.forEach(x->System.out.println(x.getB().toString()));
Thu Nov 03 12:35:23 EDT 2016
Sun Nov 06 00:00:00 EDT 2016
Mon Nov 07 14:42:18 EST 2016
Mon Nov 07 15:12:23 EST 2016
If you find something built into Jackson that will do this, I encourage you to use it, but sometimes you end up needing the extra level of customization that this method provides. Hope it helps.
Check out the question below too. It's similar, but doesn't deal with multiple formats. The accepted answer uses the custom deserializer as well.
References:
Similar SO Question
Getting started with deserializers

In Android Studio I am getting errors with Java.text.DateFormat

I am trying to change the following code, to be better used in an Android environment as part of an upcoming API.
public class DateFormatter implement JsonDeserializer<Date>,
JsonSerializer<Date> {
private final DateFormat[] formats;
public DateFormatter() {
formats = new DateFormat[3];
formats[0] = new SimpleDateFormat(DATE_FORMAT);
formats[1] = new SimpleDateFormat(DATE_FORMAT_V2_1);
formats[2] = new SimpleDateFormat(DATE_FORMAT_V2_2);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu"); //$NON-NLS-1$
for (DateFormat format : formats)
format.setTimeZone(timeZone);
}
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonParseException exception = null;
final String value = json.getAsString();
for (DateFormat format : formats)
try {
synchronized (format) {
return format.parse(value);
}
} catch (ParseException e) {
exception = new JsonParseException(e);
}
throw exception;
}
public JsonElement serialize(Date date, Type type,
JsonSerializationContext context) {
final DateFormat primary = formats[0];
String formatted;
synchronized (primary) {
formatted = primary.format(date);
}
return new JsonPrimitive(formatted);
}
}
I do not need to support v2.1 and v2.2. so I've been trying to remove the array, and code it for just a single instance. I'm running into some errors though.
Here is what I have so far:
class DateFormatter implements JsonDeserializer<Date>,
JsonSerializer<Date> {
private DateFormat formats;
DateFormatter() {
formats = new DateFormat;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu");
for (DateFormat format : formats)
format.setTimeZone(timeZone);
}
public Date deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonParseException exception = null;
final String value;
value = json.getAsString();
for (DateFormat format : formats)
try {
synchronized (format) {
return format.parse(value);
}
} catch (ParseException e) {
exception = new JsonParseException(e);
}
throw exception;
}
public JsonElement serialize(Date date, Type type,
JsonSerializationContext context) {
final DateFormat primary;
primary = formats;
String formatted;
synchronized (primary) {
formatted = primary.format(date);
}
return new JsonPrimitive(formatted);
}
}
However, once I get it this point, I get errors. The main one I'm currently concerned about is getString.
What am I doing wrong here?
Edit:
#trooper I am not able to build the project, so I can't pull a --stacktrace --debug
I changed the 2nd code block in the post to reflect my current code. I changed;
formats = new SimpleDateFormat(getString(R.string.date_format), Locale.ENGLISH);
to;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
and that corrected my first question.
So, now that is answered, moving on to my next question. As you can see I'm moving from an array in the first block to a single instance in the second. the line
for (DateFormat format : formats)
the "formats' is throwing a "foreach not applicable to java.text.DateFormat'
I know foreach is used in arrays, what I don't know is how to remove that part of the loop and achieve what i need to... this is where I get really lost.
My end goal is to Convert the current GitHib APIv3 written in Java for the Eclipse Studio which supports API v2 & v3, over to an Android GitHub API v3, seeing as we won't need to cover v2.
I hope this edit is enough information to be able to answer.
Formats is not declared as an array. You need to declare this as an array an initialize it one by one.
try this,
private final DateFormat[] formats
formats = new DateFormat[3];
formats[0] = new SimpleDateFormat(getString(R.string.date_format), Locale.ENGLISH);
to remove the loop just use
formats = new DateFormat;
formats = new SimpleDateFormat(String.valueOf(R.string.date_format), Locale.ENGLISH);
final TimeZone timeZone = TimeZone.getTimeZone("Zulu");
formats.setTimeZone(timeZone);

Unable to parse date for arabic locale

public class DateParser {
public static void main(String[] args) {
String dateString = "2015-07-20";
try
{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date dt=dateFormat.parse(dateString);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Above is my code piece. I'm trying to parse a date string. Its working fine if my locale is US. If i change it to Arabic (In calendar settings. I'm using windows machine), its not working. getting below error.
java.text.ParseException: Unparseable date: "2015-07-20"
at java.text.DateFormat.parse(Unknown Source)
at DateParser.main(DateParser.java:34)
What i'm doing wrong?

Solrj Date request

How to request by date using SolrJ?
I get as a parameter a date in this format '01/10/2014'. Then I convert this format to a Date object and convert the object to a UTC format. Here is a code example of what I am doing :
public class DateHelper {
public static final String DD_MM_YYYY_FORMAT = "dd/MM/yyyy";
public static final String SOLR_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
public static Date getDateFromString(String date, String format) {
if (StringUtils.isNotEmpty(date)) {
try {
return FastDateFormat.getInstance(format).parse(date);
} catch (ParseException e) {
LOGGER.error(e.getMessage());
}
}
return null;
}
public static String getStringFromDate(Date date, String format) {
if (date != null) {
try {
return FastDateFormat.getInstance(format).format(date);
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
}
return "";
}
public static void main(String...args){
Date dateFromString = DateHelper.getDateFromString('01/10/2014', DateHelper.DD_MM_YYYY_FORMAT);
String date = DateHelper.getStringFromDate(dateFromString, DateHelper.SOLR_DATE_FORMAT);
System.out.println(date);
}
}
This small program displays '2014-10-01T00:00:00Z'. When I try to submit this date in Solr using a filter query, I receive this error from Sorl :
org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrException: Invalid Date String:'2014-10-01T00'
Here is my Solr query :
SolrQuery solrQuery = new SolrQuery("*:*");
String date = String.format( "date:%s",dateInput);
query.addFilterQuery(date);
getSolrServer().query(solrQuery, METHOD.POST);
How can I solve this problem? THx for your help.
P.S : The class FastDateFormat is from Apache Commons Lang 3. I am using solr version 4.8.1.
This happens because of the way filterQuery is created:
String date = String.format( "date:%s",dateInput);
query.addFilterQuery(date);
That way the solr gets:
date:2014-10-01T00:00:00Z
And the exception is thrown because of the multiple : symbols that the Query Parser cannot parse correctly.
In order to fix it the special characters that are part of Query Syntax should be escaped.
From the java side it can be done this way (using ClientUtils.escapeQueryChars from SolrJ):
String date = String.format( "date:%s", ClientUtils.escapeQueryChars(dateInput));
query.addFilterQuery(date);
Syntax to query solr date field -- Date:[YYYY-MM-DDTHH:mm:ssZ]

Categories

Resources