Reputation: 1203
I have a requirement where I have to map my value from incoming request as json to Date in any of the format. For example in my request I can get the date string as any of the below format :
1. 03/22/1990 -- MM/dd/yyyy
2. 03/22/1990 12:34:45
3. 03/22/1990 12:23 AM
How can I map my incoming map value to Date.
Upvotes: 0
Views: 4550
Reputation: 14611
I think that you need to solve two problems here:
Regarding the first problem you can use JODA or Java 8. I will stick to Java 8, because the new java.time
libraries can handle the formats in your question.
Regarding JSON, I suggest to use the Jackson library, because it is extremely flexible and you can create your own custom deserialisers with it.
In order to import the Jackson library you can use the following Maven dependencies:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
The default deserializer needs to be packed into a module. Here is some sample deserializer code:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
/**
* Used to deserialize LocalTime from a multiple string formats.
*/
public class GenericDateSerializerModule extends SimpleModule {
public static final StdScalarDeserializer<LocalDateTime> DATE_TIME_STD_SCALAR_DESERIALIZER =
new StdScalarDeserializer<LocalDateTime>(LocalDate.class) {
private DateTimeFormatter[] dtfs = {
new DateTimeFormatterBuilder()
.appendPattern("MM/dd/yyyy")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter(),
DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"),
DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm a")
};
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException {
if (jsonParser.getCurrentTokenId() == JsonTokenId.ID_STRING) {
String string = jsonParser.getText().trim();
for (DateTimeFormatter dtf : dtfs) {
try {
return LocalDateTime.parse(string, dtf);
} catch(Exception e) {
System.err.println(e);
}
}
}
return null;
}
};
public GenericDateSerializerModule() {
addDeserializer(LocalDateTime.class, DATE_TIME_STD_SCALAR_DESERIALIZER);
}
}
Then you can use this simple module with serializer to map JSON to classes:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.time.LocalDateTime;
class GenericDateSerializerModuleTest {
private ObjectMapper genericDateSerializerMapper = new ObjectMapper();
@BeforeEach
void setUp() {
genericDateSerializerMapper.registerModule(new GenericDateSerializerModule());
}
@Test
void extractMultiFormatDates() throws IOException {
String json = "{\n" +
" \"bookingDate\": \"03/22/1990\",\n" +
" \"createdOn\": \"03/22/1990 12:34:45\",\n" +
" \"modifiedOn\": \"03/22/1990 12:23 AM\"\n" +
"}";
DateJson dateJson = genericDateSerializerMapper.readerFor(DateJson.class).readValue(json);
System.out.println(dateJson);
}
static class DateJson {
private LocalDateTime BookingDate;
private LocalDateTime CreatedOn;
private LocalDateTime ModifiedOn;
public LocalDateTime getBookingDate() {
return BookingDate;
}
public void setBookingDate(LocalDateTime bookingDate) {
BookingDate = bookingDate;
}
public LocalDateTime getCreatedOn() {
return CreatedOn;
}
public void setCreatedOn(LocalDateTime createdOn) {
CreatedOn = createdOn;
}
public LocalDateTime getModifiedOn() {
return ModifiedOn;
}
public void setModifiedOn(LocalDateTime modifiedOn) {
ModifiedOn = modifiedOn;
}
@Override
public String toString() {
return "DateJson{" +
"BookingDate=" + BookingDate +
", CreatedOn=" + CreatedOn +
", ModifiedOn=" + ModifiedOn +
'}';
}
}
}
If you run this test, you will see this output on the console:
java.time.format.DateTimeParseException: Text '03/22/1990 12:34:45' could not be parsed, unparsed text found at index 10
java.time.format.DateTimeParseException: Text '03/22/1990 12:23 AM' could not be parsed, unparsed text found at index 10
java.time.format.DateTimeParseException: Text '03/22/1990 12:23 AM' could not be parsed at index 16
DateJson{BookingDate=1990-03-22T00:00, CreatedOn=1990-03-22T12:34:45, ModifiedOn=1990-03-22T00:23}
Upvotes: 0
Reputation: 97
So, you can use this one solution
private Date parse(final String date) {
return parseDate(date, "MM/dd/yyyy HH:mm a")
.orElseGet(() -> parseDate(date, "MM/dd/yyyy HH:mm:ss")
.orElseGet(() -> parseDate(date, "MM/dd/yyyy").orElse(null)));
}
private Optional<Date> parseDate(String date, String pattern) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
return Optional.of(simpleDateFormat.parse(date));
} catch (ParseException e) {
return Optional.empty();
}
}
@Test
public void test() {
String date = "03/22/1990";
String date1 = "03/22/1990 12:34:45";
String date2 = "03/22/1990 12:34 AM";
System.out.println(parse(date));
System.out.println(parse(date1));
System.out.println(parse(date2));
}
Upvotes: 0
Reputation: 53
The three formats you mentioned can easily be identified with the help of regex. For example, pattern \d\d\/\d\d\/\d\d\d\d \d\d:\d\d:\d\d
would match the second string in your example, but not the other two.
Then you can use SimpleDateFormatter with the identified format. E.g.
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date date =formatter1.parse(dateString);
Upvotes: 2
Reputation:
If you need to use Java.time (for some reason) you can use something like these:
private Timestamp parseDateFromString(String dateString) {
if (StringUtils.isNotBlank(dateString)) {
try {
final DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
final Date date = df.parse(dateString);
return new Timestamp(date.getTime());
} catch (ParseException e) {
log.error("Error parsing string: " + dateString, e);
}
}
return null;
}
Upvotes: 0
Reputation: 661
I would suggest you can use JodaTime library to implement this one
You can use multiple parsers and add them to the builder by using DateTimeFormatterBuilder.append method:
DateTimeParser[] parsers = {
DateTimeFormat.forPattern( "MM/dd/yyyy" ).getParser(),
DateTimeFormat.forPattern( "MM/dd/yyyy HH:mm:ss" ).getParser(),
DateTimeFormat.forPattern( "MM/dd/yyyy HH:mm tt" ).getParser()
};
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append( null, parsers ).toFormatter();
DateTime date1 = formatter.parseDateTime( "03/22/1990" );
DateTime date2 = formatter.parseDateTime( "03/22/1990 10:34:11" );
Upvotes: 1