diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/TemporalAccessorConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/TemporalAccessorConverter.java index c5782453e..dd4541a68 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/TemporalAccessorConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/TemporalAccessorConverter.java @@ -15,21 +15,12 @@ package org.dromara.hutool.core.convert.impl; import org.dromara.hutool.core.convert.AbstractConverter; import org.dromara.hutool.core.date.DateTime; import org.dromara.hutool.core.date.DateUtil; +import org.dromara.hutool.core.date.TimeUtil; import org.dromara.hutool.core.date.format.GlobalCustomFormat; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; -import java.time.DayOfWeek; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Month; -import java.time.MonthDay; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZoneId; -import java.time.ZonedDateTime; +import java.time.*; import java.time.chrono.Era; import java.time.chrono.IsoEra; import java.time.format.DateTimeFormatter; @@ -75,7 +66,7 @@ public class TemporalAccessorConverter extends AbstractConverter { /** * 构造 * - * @param format 日期格式 + * @param format 日期格式 */ public TemporalAccessorConverter(final String format) { this.format = format; @@ -103,7 +94,7 @@ public class TemporalAccessorConverter extends AbstractConverter { protected TemporalAccessor convertInternal(final Class targetClass, final Object value) { if (value instanceof Long) { return parseFromLong(targetClass, (Long) value); - }else if (value instanceof Integer) { + } else if (value instanceof Integer) { return parseFromLong(targetClass, ((Integer) value).longValue()); } else if (value instanceof TemporalAccessor) { return parseFromTemporalAccessor(targetClass, (TemporalAccessor) value); @@ -129,20 +120,27 @@ public class TemporalAccessorConverter extends AbstractConverter { return null; } - if(DayOfWeek.class == targetClass){ + if (DayOfWeek.class == targetClass) { return DayOfWeek.valueOf(StrUtil.toString(value)); - } else if(Month.class == targetClass){ + } else if (Month.class == targetClass) { return Month.valueOf(StrUtil.toString(value)); - } else if(Era.class == targetClass){ + } else if (Era.class == targetClass) { return IsoEra.valueOf(StrUtil.toString(value)); - } else if(MonthDay.class == targetClass){ + } else if (MonthDay.class == targetClass) { return MonthDay.parse(value); } final Instant instant; final ZoneId zoneId; if (null != this.format) { - final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(this.format); + final DateTimeFormatter formatter = TimeUtil.ofPattern(this.format); + + // issue#I9HQQE + final TemporalAccessor temporalAccessor = parseWithFormat(targetClass, value, formatter); + if(null != temporalAccessor){ + return temporalAccessor; + } + instant = formatter.parse(value, Instant::from); zoneId = formatter.getZone(); } else { @@ -153,28 +151,48 @@ public class TemporalAccessorConverter extends AbstractConverter { return parseFromInstant(targetClass, instant, zoneId); } + /** + * 对于自定义格式的字符串,单独解析为{@link TemporalAccessor} + * + * @param targetClass 目标类型 + * @param value 日期字符串 + * @param formatter 格式 + * @return {@link TemporalAccessor} + */ + private TemporalAccessor parseWithFormat(final Class targetClass, final CharSequence value, final DateTimeFormatter formatter) { + // issue#I9HQQE + if (LocalDate.class == targetClass) { + return LocalDate.parse(value, formatter); + } else if (LocalDateTime.class == targetClass) { + return LocalDateTime.parse(value, formatter); + } else if (LocalTime.class == targetClass) { + return LocalTime.parse(value, formatter); + } + return null; + } + /** * 将Long型时间戳转换为java.time中的对象 * * @param targetClass 目标类型 - * @param time 时间戳 + * @param time 时间戳 * @return java.time中的对象 */ private TemporalAccessor parseFromLong(final Class targetClass, final Long time) { - if(targetClass == Month.class){ + if (targetClass == Month.class) { return Month.of(Math.toIntExact(time)); - } else if(targetClass == DayOfWeek.class){ + } else if (targetClass == DayOfWeek.class) { return DayOfWeek.of(Math.toIntExact(time)); - } else if(Era.class == targetClass){ + } else if (Era.class == targetClass) { return IsoEra.of(Math.toIntExact(time)); } final Instant instant; - if(GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)){ + if (GlobalCustomFormat.FORMAT_SECONDS.equals(this.format)) { // https://gitee.com/dromara/hutool/issues/I6IS5B // Unix时间戳 instant = Instant.ofEpochSecond(time); - }else{ + } else { instant = Instant.ofEpochMilli(time); } return parseFromInstant(targetClass, instant, null); @@ -187,11 +205,11 @@ public class TemporalAccessorConverter extends AbstractConverter { * @return java.time中的对象 */ private TemporalAccessor parseFromTemporalAccessor(final Class targetClass, final TemporalAccessor temporalAccessor) { - if(DayOfWeek.class == targetClass){ + if (DayOfWeek.class == targetClass) { return DayOfWeek.from(temporalAccessor); - } else if(Month.class == targetClass){ + } else if (Month.class == targetClass) { return Month.from(temporalAccessor); - } else if(MonthDay.class == targetClass){ + } else if (MonthDay.class == targetClass) { return MonthDay.from(temporalAccessor); } @@ -212,7 +230,7 @@ public class TemporalAccessorConverter extends AbstractConverter { /** * 将TemporalAccessor型时间戳转换为java.time中的对象 * - * @param targetClass 目标类 + * @param targetClass 目标类 * @param localDateTime {@link LocalDateTime}对象 * @return java.time中的对象 */ diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/TimeUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/TimeUtil.java index bc2cb1b97..e550092ac 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/date/TimeUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/TimeUtil.java @@ -21,6 +21,7 @@ import java.time.*; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.*; import java.util.Date; import java.util.TimeZone; @@ -167,37 +168,37 @@ public class TimeUtil extends TemporalAccessorUtil { if (temporalAccessor instanceof LocalDate) { return ((LocalDate) temporalAccessor).atStartOfDay(); - } else if(temporalAccessor instanceof Instant){ + } else if (temporalAccessor instanceof Instant) { return LocalDateTime.ofInstant((Instant) temporalAccessor, ZoneId.systemDefault()); } // issue#3301 - try{ + try { return LocalDateTime.from(temporalAccessor); - } catch (final Exception ignore){ + } catch (final Exception ignore) { //ignore } - try{ + try { return ZonedDateTime.from(temporalAccessor).toLocalDateTime(); - } catch (final Exception ignore){ + } catch (final Exception ignore) { //ignore } - try{ + try { return LocalDateTime.ofInstant(Instant.from(temporalAccessor), ZoneId.systemDefault()); - } catch (final Exception ignore){ + } catch (final Exception ignore) { //ignore } return LocalDateTime.of( - TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND) + TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND) ); } @@ -220,9 +221,9 @@ public class TimeUtil extends TemporalAccessorUtil { } return LocalDate.of( - TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR), - TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH) + TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR), + TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH) ); } @@ -605,4 +606,22 @@ public class TimeUtil extends TemporalAccessorUtil { public static boolean isSameDay(final ChronoLocalDate date1, final ChronoLocalDate date2) { return date1 != null && date2 != null && date1.isEqual(date2); } + + /** + * 通过日期时间字符串构建{@link DateTimeFormatter} + * + * @param pattern 格式,如yyyy-MM-dd + * @return {@link DateTimeFormatter} + * @since 6.0.0 + */ + public static DateTimeFormatter ofPattern(final String pattern) { + return new DateTimeFormatterBuilder() + .appendPattern(pattern) + // + .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) + .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0) + .toFormatter(); + } } diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9HQQETest.java b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9HQQETest.java new file mode 100644 index 000000000..0c5d5d30c --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/IssueI9HQQETest.java @@ -0,0 +1,33 @@ +package org.dromara.hutool.json; + +import lombok.Data; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public class IssueI9HQQETest { + + @Test + public void toBeanTest(){ + final String json = "{\"currentDate\":\"18/04/2024\", \"currentDateTime\":\"18/04/2024\"}"; + final JSONConfig jsonConfig = new JSONConfig(); + jsonConfig.setDateFormat("dd/MM/yyyy"); + + final JSONObject entries = JSONUtil.parseObj(json, jsonConfig); + + final MMHBo mmh = entries.toBean(MMHBo.class); + Assertions.assertNotNull(mmh.getCurrentDate()); + Assertions.assertNotNull(mmh.getCurrentDateTime()); + } + + @Data + public static class MMHBo { + /** + * 当前时间 + */ + private LocalDate currentDate; + private LocalDateTime currentDateTime; + } +}