diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeUtil.java new file mode 100644 index 0000000..ca4e006 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeUtil.java @@ -0,0 +1,282 @@ +package xyz.zhouxy.plusone.commons.util; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.Date; +import java.util.Objects; +import java.util.TimeZone; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTimeZone; + +public class DateTimeUtil { + + private static final MapWrapper DATE_TIME_FORMATTER_CHCHE = MapWrapper + .wrapHashMap() + .keyChecker(StringUtils::isNotBlank) + .valueChecker(Objects::nonNull) + .build(); + + public static DateTimeFormatter getDateTimeFormatter(String pattern) { + if (!DATE_TIME_FORMATTER_CHCHE.containsKey(pattern)) { + synchronized (DateTimeUtil.class) { + if (!DATE_TIME_FORMATTER_CHCHE.containsKey(pattern)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + DATE_TIME_FORMATTER_CHCHE.put(pattern, formatter); + return formatter; + } + } + } + return DATE_TIME_FORMATTER_CHCHE.get(pattern) + .orElseThrow(() -> new IllegalStateException("Formatter does not exist.")); + } + + public static String toString(String pattern, ZonedDateTime dateTime) { + return getDateTimeFormatter(pattern).format(dateTime); + } + + public static String toString(String pattern, Instant instant) { + ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault()); + return toString(pattern, dateTime); + } + + public static String toString(String pattern, Instant instant, ZoneId zone) { + ZonedDateTime dateTime = instant.atZone(zone); + return toString(pattern, dateTime); + } + + public static String nowStr(String pattern) { + return toString(pattern, ZonedDateTime.now()); + } + + public static String nowStr(String pattern, ZoneId zone) { + return toString(pattern, Instant.now().atZone(zone)); + } + + // toDate + + public static Date toDate(long timeMillis) { + return Date.from(Instant.ofEpochMilli(timeMillis)); + } + + public static Date toDate(Calendar calendar) { + return calendar.getTime(); + } + + public static Date toDate(Instant instant) { + return Date.from(instant); + } + + public static Date toDate(ZonedDateTime zonedDateTime) { + return Date.from(zonedDateTime.toInstant()); + } + + public static Date toDate(LocalDateTime localDateTime, ZoneId zone) { + return Date.from(ZonedDateTime.of(localDateTime, zone).toInstant()); + } + + public static Date toDate(LocalDate localDate, LocalTime localTime, ZoneId zone) { + return Date.from(ZonedDateTime.of(localDate, localTime, zone).toInstant()); + } + + // toInstant + + public static Instant toInstant(long timeMillis) { + return Instant.ofEpochMilli(timeMillis); + } + + public static Instant toInstant(Date date) { + return date.toInstant(); + } + + public static Instant toInstant(Calendar calendar) { + return calendar.toInstant(); + } + + /** + * 获取 {@link Instant} 对象 + * + * @param zonedDateTime 带时区信息的地区时间 + * @return 时间点 + * + * @deprecated 使用 {@link ZonedDateTime#toInstant()} + */ + @Deprecated + public static Instant toInstant(ZonedDateTime zonedDateTime) { + return zonedDateTime.toInstant(); + } + + public static Instant toInstant(LocalDateTime localDateTime, ZoneId zone) { + return ZonedDateTime.of(localDateTime, zone).toInstant(); + } + + // toZonedDateTime + + /** + * 获取时间戳在指定时区的地区时间。 + *

+ * 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳, + * 只是不同时区的表示。 + *

+ * + * @param dateTime {@link Date} 对象 + * @param zone 时区 + * @return 带时区信息的地区时间 + */ + public static ZonedDateTime toZonedDateTime(long timeMillis, ZoneId zone) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone); + } + + /** + * 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。 + *

+ * 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上还是同一时间戳, + * 只是不同时区的表示。 + *

+ * + * @param dateTime {@link Date} 对象 + * @param zone 时区 + * @return 带时区信息的地区时间 + */ + public static ZonedDateTime toZonedDateTime(Date dateTime, ZoneId zone) { + return ZonedDateTime.ofInstant(dateTime.toInstant(), zone); + } + + /** + * 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。 + *

+ * 传入不同 {@link ZoneId},获取到的 {@link ZonedDateTime} 对象实际上表示的还是还是同一时间戳的时间, + * 只是不同时区的表示。 + *

+ * + * @param dateTime {@link Date} 对象 + * @param timeZone 时区 + * @return 带时区信息的地区时间 + */ + public static ZonedDateTime toZonedDateTime(Date dateTime, TimeZone timeZone) { + return ZonedDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId()); + } + + public static ZonedDateTime toZonedDateTime(Calendar calendar, ZoneId zone) { + return calendar.toInstant().atZone(zone); + } + + public static ZonedDateTime toZonedDateTime(Calendar calendar, TimeZone zone) { + return calendar.toInstant().atZone(zone.toZoneId()); + } + + /** + * 创建带时区的地区时间 + * + * @param localDateTime 地区时间 + * @param zone 时区 + * @return 带时区的地区时间 + * + * @deprecated 使用 {@link ZonedDateTime#of(LocalDateTime, ZoneId)} + */ + @Deprecated + public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, ZoneId zone) { + return ZonedDateTime.of(localDateTime, zone); + } + + // toLocalDateTime + + /** + * 获取时间戳在指定时区的地区时间。 + * + * @param dateTime {@link Date} 对象 + * @param zone 时区 + * @return 地区时间 + */ + public static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zone) { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), zone); + } + + /** + * 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。 + * + * @param dateTime {@link Date} 对象 + * @param zone 时区 + * @return 地区时间 + */ + public static LocalDateTime toLocalDateTime(Date dateTime, ZoneId zone) { + return LocalDateTime.ofInstant(dateTime.toInstant(), zone); + } + + /** + * 获取 {@link Date} 所表示的时间戳,在指定时区的地区时间。 + * + * @param dateTime {@link Date} 对象 + * @param timeZone 时区 + * @return 地区时间 + */ + public static LocalDateTime toLocalDateTime(Date dateTime, TimeZone timeZone) { + return LocalDateTime.ofInstant(dateTime.toInstant(), timeZone.toZoneId()); + } + + public static LocalDateTime toLocalDateTime(Calendar calendar, ZoneId zone) { + return LocalDateTime.ofInstant(calendar.toInstant(), zone); + } + + public static LocalDateTime toLocalDateTime(Calendar calendar, TimeZone zone) { + return LocalDateTime.ofInstant(calendar.toInstant(), zone.toZoneId()); + } + + public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime, ZoneId zone) { + return LocalDateTime.ofInstant(zonedDateTime.toInstant(), zone); + } + + // ==================== + public static org.joda.time.Instant toJodaInstant(java.time.Instant instant) { + return new org.joda.time.Instant(instant.toEpochMilli()); + } + + public static org.joda.time.Instant toJodaInstant(java.time.ZonedDateTime zonedDateTime) { + return new org.joda.time.Instant(zonedDateTime.toInstant().toEpochMilli()); + } + + public static java.time.Instant toJavaInstant(org.joda.time.Instant instant) { + return toInstant(instant.getMillis()); + } + + public static java.time.Instant toJavaInstant(org.joda.time.DateTime dateTime) { + return toInstant(dateTime.getMillis()); + } + + public static org.joda.time.DateTime toJodaDateTime(java.time.ZonedDateTime zonedDateTime) { + org.joda.time.DateTimeZone zone = org.joda.time.DateTimeZone.forID(zonedDateTime.getZone().getId()); + return toJodaInstant(zonedDateTime.toInstant()).toDateTime(zone); + } + + public static org.joda.time.DateTime toJodaDateTime(java.time.Instant instant, ZoneId zone) { + org.joda.time.DateTimeZone dateTimeZone = org.joda.time.DateTimeZone.forID(zone.getId()); + return toJodaInstant(instant).toDateTime(dateTimeZone); + } + + public static java.time.ZonedDateTime toZonedDateTime(org.joda.time.DateTime dateTime) { + ZoneId zone = dateTime.getZone().toTimeZone().toZoneId(); + return toJavaInstant(dateTime.toInstant()).atZone(zone); + } + + public static java.time.ZonedDateTime toZonedDateTime( + org.joda.time.Instant instant, + org.joda.time.DateTimeZone dateTimeZone) { + ZoneId zone = dateTimeZone.toTimeZone().toZoneId(); + return toJavaInstant(instant).atZone(zone); + } + + public static org.joda.time.LocalDateTime toJodaLocalDateTime(java.time.LocalDateTime localDateTime) { + long instant = toInstant(localDateTime, ZoneId.systemDefault()).toEpochMilli(); + return new org.joda.time.LocalDateTime(instant, DateTimeZone.getDefault()); + } + + private DateTimeUtil() { + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeUtilTests.java b/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeUtilTests.java new file mode 100644 index 0000000..b421f33 --- /dev/null +++ b/src/test/java/xyz/zhouxy/plusone/commons/util/DateTimeUtilTests.java @@ -0,0 +1,58 @@ +package xyz.zhouxy.plusone.commons.util; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class DateTimeUtilTests { + + private static final Logger log = LoggerFactory.getLogger(DateTimeUtilTests.class); + + @Test + void testLocalNowStr() { + log.info(DateTimeUtil.nowStr("yyyy/MM/dd HH:mm:ss.SSS")); + } + + @Test + void testToJoda() { + LocalDateTime now = LocalDateTime.now(); + log.info("now: {}", now); + org.joda.time.LocalDateTime now2 = DateTimeUtil.toJodaLocalDateTime(now); + log.info("now2: {}", now2); + } + + @Test + void testToInstant() { + Instant now = DateTimeUtil.toInstant(System.currentTimeMillis()); + String str = DateTimeUtil.toString("yy-M-d HH:mm:ss.SSS", now); + log.info(str); + } + + @Test + void testToJodaDateTime() { + DateTime jodaDateTime = DateTimeUtil.toJodaDateTime(Instant.now(), ZoneId.of("null")); + log.info("jodaDateTime: {}", jodaDateTime); + } + + @Test + void test() { + Instant now = Instant.now(); + DateTime jodaDateTime = DateTimeUtil.toJodaDateTime(now, ZoneId.of("America/New_York")); + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS"); + log.info(formatter.print(jodaDateTime)); + log.info(jodaDateTime.getZone().toString()); + log.info(jodaDateTime.toString()); + log.info("=========================================="); + org.joda.time.Instant instant = new org.joda.time.Instant(System.currentTimeMillis() - 500000); + log.info(instant.toString()); + log.info(DateTimeUtil.toJavaInstant(instant).toString()); + log.info(DateTimeUtil.toZonedDateTime(instant, DateTimeZone.forID("America/New_York")).toString()); + } +}