1616 */
1717package org .apache .commons .beanutils2 .converters ;
1818
19+ import org .apache .commons .beanutils2 .ConversionException ;
20+
1921import java .text .DateFormat ;
2022import java .text .ParsePosition ;
2123import java .text .SimpleDateFormat ;
2527import java .time .OffsetDateTime ;
2628import java .time .ZoneId ;
2729import java .time .ZonedDateTime ;
30+ import java .time .format .DateTimeParseException ;
2831import java .util .Calendar ;
2932import java .util .Date ;
3033import java .util .Locale ;
3134import java .util .TimeZone ;
3235
33- import org .apache .commons .beanutils2 .ConversionException ;
34-
3536/**
3637 * {@link org.apache.commons.beanutils2.Converter} implementation
3738 * that handles conversion to and from <b>date/time</b> objects.
4445 * <li>{@code java.time.LocalDate}</li>
4546 * <li>{@code java.time.LocalDateTime}</li>
4647 * <li>{@code java.time.OffsetDateTime}</li>
48+ * <li>{@code java.time.Instant}</li>
4749 * <li>{@code java.time.ZonedDateTime}</li>
4850 * <li>{@code java.sql.Date}</li>
4951 * <li>{@code java.sql.Time}</li>
@@ -228,19 +230,21 @@ protected String convertToString(final Object value) throws Throwable {
228230
229231 Date date = null ;
230232 if (value instanceof Date ) {
231- date = (Date )value ;
233+ date = (Date ) value ;
232234 } else if (value instanceof Calendar ) {
233- date = ((Calendar )value ).getTime ();
235+ date = ((Calendar ) value ).getTime ();
234236 } else if (value instanceof Long ) {
235- date = new Date (((Long )value ).longValue ());
237+ date = new Date (((Long ) value ).longValue ());
236238 } else if (value instanceof LocalDateTime ) {
237- date = java .sql .Timestamp .valueOf (((LocalDateTime )value ));
239+ date = java .sql .Timestamp .valueOf (((LocalDateTime ) value ));
238240 } else if (value instanceof LocalDate ) {
239- date = java .sql .Date .valueOf (((LocalDate )value ));
241+ date = java .sql .Date .valueOf (((LocalDate ) value ));
240242 } else if (value instanceof ZonedDateTime ) {
241- date = Date .from (((ZonedDateTime )value ).toInstant ());
243+ date = Date .from (((ZonedDateTime ) value ).toInstant ());
242244 } else if (value instanceof OffsetDateTime ) {
243- date = Date .from (((OffsetDateTime )value ).toInstant ());
245+ date = Date .from (((OffsetDateTime ) value ).toInstant ());
246+ } else if (value instanceof Instant ) {
247+ date = Date .from (((Instant ) value ));
244248 }
245249
246250 String result = null ;
@@ -260,7 +264,7 @@ protected String convertToString(final Object value) throws Throwable {
260264 result = value .toString ();
261265 if (log ().isDebugEnabled ()) {
262266 log ().debug (" Converted to String using toString() '" + result + "'" );
263- }
267+ }
264268 }
265269 return result ;
266270 }
@@ -277,6 +281,7 @@ protected String convertToString(final Object value) throws Throwable {
277281 * <li>{@code java.time.LocalDate}</li>
278282 * <li>{@code java.time.LocalDateTime}</li>
279283 * <li>{@code java.time.OffsetDateTime}</li>
284+ * <li>{@code java.time.Instant}</li>
280285 * <li>{@code java.time.ZonedDateTime}</li>
281286 * <li>{@code java.sql.Date}</li>
282287 * <li>{@code java.sql.Time}</li>
@@ -320,46 +325,51 @@ protected <T> T convertToType(final Class<T> targetType, final Object value) thr
320325
321326 // Handle Date (includes java.sql.Date & java.sql.Time)
322327 if (value instanceof Date ) {
323- final Date date = (Date )value ;
328+ final Date date = (Date ) value ;
324329 return toDate (targetType , date .getTime ());
325330 }
326331
327332 // Handle Calendar
328333 if (value instanceof Calendar ) {
329- final Calendar calendar = (Calendar )value ;
334+ final Calendar calendar = (Calendar ) value ;
330335 return toDate (targetType , calendar .getTime ().getTime ());
331336 }
332337
333338 // Handle Long
334339 if (value instanceof Long ) {
335- final Long longObj = (Long )value ;
340+ final Long longObj = (Long ) value ;
336341 return toDate (targetType , longObj .longValue ());
337342 }
338343
339344 // Handle LocalDate
340345 if (value instanceof LocalDate ) {
341- final LocalDate date = (LocalDate )value ;
346+ final LocalDate date = (LocalDate ) value ;
342347 return toDate (targetType , date .atStartOfDay (getZoneId ()).toInstant ().toEpochMilli ());
343348 }
344349
345350 // Handle LocalDateTime
346351 if (value instanceof LocalDateTime ) {
347- final LocalDateTime date = (LocalDateTime )value ;
352+ final LocalDateTime date = (LocalDateTime ) value ;
348353 return toDate (targetType , date .atZone (getZoneId ()).toInstant ().toEpochMilli ());
349354 }
350355
351356 // Handle ZonedDateTime
352357 if (value instanceof ZonedDateTime ) {
353- final ZonedDateTime date = (ZonedDateTime )value ;
358+ final ZonedDateTime date = (ZonedDateTime ) value ;
354359 return toDate (targetType , date .toInstant ().toEpochMilli ());
355360 }
356361
357362 // Handle OffsetDateTime
358363 if (value instanceof OffsetDateTime ) {
359- final OffsetDateTime date = (OffsetDateTime )value ;
364+ final OffsetDateTime date = (OffsetDateTime ) value ;
360365 return toDate (targetType , date .toInstant ().toEpochMilli ());
361366 }
362367
368+ if (value instanceof Instant ) {
369+ final Instant date = (Instant ) value ;
370+ return toDate (targetType , date .toEpochMilli ());
371+ }
372+
363373 // Convert all other types to String & handle
364374 final String stringValue = toTrim (value );
365375 if (stringValue .isEmpty ()) {
@@ -454,6 +464,10 @@ private <T> T toDate(final Class<T> type, final long value) {
454464 return type .cast (offsetDateTime );
455465 }
456466
467+ if (type .equals (Instant .class )) {
468+ return type .cast (Instant .ofEpochMilli (value ));
469+ }
470+
457471 // java.util.Calendar
458472 if (type .equals (Calendar .class )) {
459473 Calendar calendar = null ;
@@ -487,6 +501,7 @@ private <T> T toDate(final Class<T> type, final long value) {
487501 * <li>{@code java.sql.Date}</li>
488502 * <li>{@code java.sql.Time}</li>
489503 * <li>{@code java.sql.Timestamp}</li>
504+ * <li>{@code java.time.Instant}</li>
490505 * </ul>
491506 * <p>
492507 * <strong>N.B.</strong> No default String conversion
@@ -530,6 +545,14 @@ private <T> T toDate(final Class<T> type, final String value) {
530545 }
531546 }
532547
548+ if (type .equals (Instant .class )) {
549+ try {
550+ return type .cast (Instant .parse (value ));
551+ } catch (final DateTimeParseException ex ) {
552+ throw new ConversionException ("String must be in ISO-8601 format to create a java.time.Instant" );
553+ }
554+ }
555+
533556 final String msg = toString (getClass ()) + " does not support default String to '"
534557 + toString (type ) + "' conversion." ;
535558 if (log ().isWarnEnabled ()) {
0 commit comments