DateTimeFormat exception when trying to set ZonedDateTime - spring-boot

I am trying to set ZonedDateTime in request field as. -
.date(ZonedDateTime.now(ZoneId.of(ZONE_ID_EST)))
Request Model filed is -
#JsonSerialize(using = ZonedDateTimeSerializer.class)
#JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSX", shape = JsonFormat.Shape.STRING)
ZonedDateTime date;
but I am getting java.time.format.DateTimeParseException: Text '2020-06-30T21:19:08.142000-04' could not be parsed at index 26
I have tried below but same error
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSX");
.......
ZonedDateTime date = ZonedDateTime.now(ZoneId.of(ZONE_ID_EST));
String formattedString = date.format(DATE_TIME_FORMATTER);
ZonedDateTime parsedDate = ZonedDateTime.parse(formattedString)
.........
.date(ZonedDateTime.parse(formattedString))
Can someone tell me what I am doing wrong here.

Related

How to save elasticsearch date type in spring data?

I want to use spring data to get elasticsearch documents, but encountered some problems with get data.
Here is my code.
Entity:
#Id
private String id;
#Field(name = "#timestamp", type = FieldType.Date)
private Date timestamp;
#Field(name = "netflow.first_switched", type = FieldType.Date)
private Date firstSwitched;
#Field(name = "netflow.last_switched", type = FieldType.Date)
private Date lastSwitched;
My data in elasticsearch:
I want to test spring data can get document or not(implement ElasticsearchRepository), so I hard code ID like:
Optional<OriginalData> a = originalDataService.findById("nfQ8KHMBB49SfiIiH2rK");
And then I got an exception:
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2020-07-07T07:44:54.878Z'; nested exception is java.lang.IllegalArgumentException
so I modify my Entity code to
#Id
private String id;
// #Field(name = "#timestamp", type = FieldType.Date)
// private Date timestamp;
#Field(name = "netflow.first_switched", type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime firstSwitched;
#Field(name = "netflow.last_switched", type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime lastSwitched;
still wrong, but got another exception:
org.springframework.data.elasticsearch.core.convert.ConversionException: could not create object of class java.time.LocalDateTime
My questions are:
How to use spring data get elasticsearch document with field containing data type?
I want to get field "#timestamp", can I get this?
Does anyone can help me, please?
Kase

How to convert LocalDateTime to OffsetDateTime?

How to convert LocalDateTime to OffsetDateTime?
private OffsetDateTime getEntryDate(Payment payment) {
return Optional.ofNullable(payment)
.map(Payment::getEntryDate)
.map(SHOULD RETURN OffsetDateTime)
.orElse(null);
}
Payment::getEntryDate will return LocalDateTime
There are many ways to convert LocalDateTime to OffsetDateTime. Some of them are listed below:
1. Using LocalDateTime#atOffset​(ZoneOffset offset):
LocalDateTime ldt = LocalDateTime.now();
ZoneOffset offset = ZoneOffset.UTC;
OffsetDateTime odt = ldt.atOffset(offset);
2. Using LocalDateTime#atZone​(ZoneId zone) => ZonedDateTime#toOffsetDateTime():
LocalDateTime ldt = LocalDateTime.now();
// Change the ZoneId as required e.g. ZoneId.of("Europe/London")
ZoneId zoneId = ZoneId.systemDefault();
OffsetDateTime odt = ldt.atZone(zoneId).toOffsetDateTime();
3. Using OffsetDateTime#of​(LocalDateTime dateTime, ZoneOffset offset):
LocalDateTime ldt = LocalDateTime.now();
ZoneOffset offset = ZoneOffset.UTC;
OffsetDateTime odt = OffsetDateTime.of(ldt, offset);
4. ZonedDateTime#of​(LocalDateTime localDateTime, ZoneId zone) => ZonedDateTime#toOffsetDateTime():
LocalDateTime ldt = LocalDateTime.now();
// Change the ZoneId as required e.g. ZoneId.of("Europe/London")
ZoneId zoneId = ZoneId.systemDefault();
OffsetDateTime odt = ZonedDateTime.of(ldt, zoneId).toOffsetDateTime();
Notes:
In all the solutions given above, replace the sample ZoneOffset as required e.g. ZoneOffset offset = ZoneOffset.of("+02:00").
In all the solutions given above, replace the sample LocalDateTime as required e.g. LocalDateTime ldt = LocalDateTime.of(2021, 3, 14, 10, 20).
You need to obtain the ZoneOffset to use when creating your OffsetDateTime. One approach is to use a ZoneId for your location:
final ZoneId zone = ZoneId.of("Europe/Paris");
LocalDateTime localDateTime = LocalDateTime.now();
ZoneOffset zoneOffSet = zone.getRules().getOffset(localDateTime);
OffsetDateTime offsetDateTime = localDateTime.atOffset(zoneOffSet);
System.out.println(offsetDateTime); // 2019-08-08T09:54:10.761+02:00
How about:
OffsetDateTime convertToOffsetDateTime(LocalDateTime ldt) {
ZoneOffset offset = OffsetDateTime.now().getOffset();
OffsetDateTime offsetDateTime = ldt.atOffset(offset);
return offsetDateTime;
}
An OffsetDateTime is just a date time with an offset from UTC.
So if you have a fixed offset (e.g. +02 from UTC), you can convert the localDateTime like this :
OffsetDateTime.of(localDateTime, ZoneOffset.of("+2"));
OffsetDateTime.of(localDateTime, ZoneOffset.of("+02"));
OffsetDateTime.of(localDateTime, ZoneOffset.of("+02:00"));
Most of the time you want to have the offset of a specific timezone, in this case it would be preferable to use a ZonedDateTime because for most timezone the offset is not the same in summer/winter and ZonedDateTime will automatically handle it for you.
If you absolutely want an OffsetDateTime with an offset from a specific timezone, you can write :
localDateTime.atZone(ZoneId.of("Europe/Paris")).toOffsetDateTime();
Here is my solution:
public Instant toInstant(LocalDate date) {
return date
.atStartOfDay()
.toInstant(ZoneOffset.UTC);
}
public OffsetDateTime toOffsetDateTime(LocalDate date) {
return OffsetDateTime.ofInstant(
toInstant(date),
ZoneOffset.UTC
);
}
If you want to convert a specific LocalDateTime to an OffsetDateTime this might help you:
final LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime = " + localDateTime);
final ZoneOffset offset = ZoneOffset.ofHours(3);
final OffsetDateTime offsetDateTimeRef = OffsetDateTime.now(offset);
System.out.println("offsetDateTimeRef = " + offsetDateTimeRef);
final OffsetDateTime offsetDateTimeFromLocalDateTime = OffsetDateTime.ofInstant(localDateTime.toInstant(ZoneId.systemDefault().getRules().getOffset(localDateTime)), offset);
System.out.println("offsetDateTimeFromLocalDateTime = " + offsetDateTimeFromLocalDateTime);
Output:
localDateTime = 2022-11-11T23:58:34.260550200
offsetDateTimeRef = 2022-11-12T01:58:34.262501700+03:00
offsetDateTimeFromLocalDateTime = 2022-11-12T01:58:34.260550200+03:00

LocalDateTime to java.sql.Date in java 8?

How to convert LocalDateTime to java.sql.Date in java-8?
My search on internet mostly give me Timestamp related code or LocalDate to java.sql.Date. I'm looking for LocalDateTime to java.sql.Date.
There is no direct correlation between LocalDateTime and java.sql.Date, since former is-a timestamp, and latter is-a Date.
There is, however, a relation between LocalDate and java.sql.Date, and conversion can be done like this:
LocalDate date = //your local date
java.sql.Date sqlDate = java.sql.Date.valueOf(date)
Which for any given LocalDateTime gives you the following code:
LocalDateTime dateTime = // your ldt
java.sql.Date sqlDate = java.sql.Date.valueOf(dateTime.toLocalDate());
#M. Prokhorov's answer is correct, I just want to add a few points.
A java.sql.Date keeps only the day, month and year values. The time values (hour, minute, seconds and milliseconds) are all set to zero. So, when converting a LocalDateTime to a java.sql.Date, these fields are lost.
If you're doing a one-way conversion and don't mind losing those fields, then it's ok to do it:
LocalDateTime dt = // LocalDateTime value
// convert to Date (time information is lost)
java.sql.Date date = java.sql.Date.valueOf(dt.toLocalDate());
But if you want to restore the original LocalDateTime later, it's better to save the time fields separetely, so you can recover it:
LocalDateTime dt = // your LocalDateTime
// save time information (hour, minute, seconds, fraction of seconds)
LocalTime savedTime = dt.toLocalTime();
// convert to Date (time information is lost)
java.sql.Date date = java.sql.Date.valueOf(dt.toLocalDate());
// retrieve back the LocalDate (only day/month/year)
LocalDate localDate = date.toLocalDate();
// retrieve the LocalDateTime, with the original time values
LocalDateTime ldt = localDate.atTime(savedTime);
It is possible to convert from LocalDateTime to java.sql.date while retaining the time part without havng to make assumptions about the time-zone by using java.util.Date as an intermediary:
LocalDateTime dateValue = // your LocalDateTime
java.util.Date utilDate;
String dateFormat = "yyyy-MM-dd'T'HH:mm:ss";
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern(dateFormat);
SimpleDateFormat sdf1 = new SimpleDateFormat(dateFormat);
try {
utilDate = sdf1.parse(dateValue.format(dtf1));
} catch (ParseException e) {
utilDate = null; // handle the exception
}
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());

Spring mvc ZonedDateTime conversion to UTC

I woudl ike to convert all java8 ZonedDateTimes into UTC time zone on the server side of the application. I am successfully binding the Java 8 jsr310 date data types into a spring RestController using the #DateTimeFormat.
#RequestMapping(value = "rest/test-date", method = RequestMethod.GET)
public TestCollection findPrivilegesByRoleList(
#RequestParam(value = "local-date", defaultValue = "2015-05-10") #DateTimeFormat(iso = ISO.DATE) LocalDate requestParamDate,
#RequestParam(value = "local-date-time", defaultValue = "2015-05-16T15:55:56") #DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime requestParamLocalDateTime,
#RequestParam(value = "zoned-date-time", defaultValue = "2015-05-18T11:55:56-04:00") #DateTimeFormat(iso = ISO.DATE_TIME) ZonedDateTime requestParamZonedDateTime
)
For the ZonedDateTime class, I would like to shift all input ZonedDateTimes to UTC time, so the server side is always working in UTC timezone. Following best practice #3 - Store it in UTC
http://apiux.com/2013/03/20/5-laws-api-dates-and-times/#comments
For JSON deserialization, I have a custom deserializer for ZonedDateTime that shifts any timezone into UTC.
....
//Parse string into a zoned date time with the specified timezone offset - EST, CET, EDT, PST, ect.
ZonedDateTime zonedDateTimewithTimeZone = ZonedDateTime.parse(string, formatter);
//Shift the date time to UTC Time
return zonedDateTimewithTimeZone.withZoneSameInstant(ZoneId.of("UTC"));
What is the best way to do the conversion in the controller binding? I understand this may be forcing multiple responsibilities into the same class, however I want to avoid adding the
ZonedDateTime.withZoneSameInstant
call for every date in every controller.
Thanks

how to avoid rejected value [] issue in spring form submission

i have two dates in form submission in Spring 3 + Hibernate.
#Column(name = "FinStartDate")
private Date finStartDate;
#Column(name = "FinEndDate")
private Date finEndDate;
I'm display/hide dates on the basis of some criteria. When the dates are hidden and submit the form, the following errors
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'register' on field 'obj.finEndDate': rejected value []; codes [typeMismatch]
How to avoid the issue.
#JsonDeserialize(using = LocalDateDeserializer.class)
#JsonSerialize(using = LocalDateSerializer.class)
#DateTimeFormat(pattern = "dd.MM.yyyy")
private Date finEndDate;
Maybe, you should use serializer/deserializer.
I think that you miss a formatter to convert the date String to a Date object.
You can try to annotate your field
#DateTimeFormat(pattern = "yyyy-MM-dd")
or to declare a initbinder in your controller like :
#InitBinder
protected void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, false));
}
Or you can declare a formatter in you mvc configuration file that will format every Date object your application is binding to.
Add #DateTimeFormat annotation for following way. If not working update date format. (MM-dd-yyyy, dd-MM-yyyy)
#Column(name = "FinEndDate")
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date finEndDate;

Resources