diff --git a/CHANGELOG.md b/CHANGELOG.md index 056710fe3..dd2896895 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ # 🚀Changelog ------------------------------------------------------------------------------------------------------------- -# 5.8.35(2024-12-08) +# 5.8.35(2024-12-15) ### 🐣新特性 * 【poi 】 优化ExcelWriter中使用比较器writer的方法,只对第一条数据进行排序(pr#3807@Github) * 【extra 】 优化Ftp.download,返回false抛出异常(issue#3805@Github) * 【core 】 优化MAC地址正则(issue#IB95X4@Gitee) * 【json 】 JSON的getByPath方法新增更为通用的指定出参类型重载(pr#3814@Github) +* 【core 】 DateUtil.parseUTC方法标记废弃,改名为parseISO8601(issue#IBB6I5@Gitee) ### 🐞Bug修复 * 【crypto 】 修复JWTSignerUtil.createSigner中algorithmId未转换问题(issue#3806@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index ab92c8519..1dee902f2 100755 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -844,16 +844,37 @@ public class DateUtil extends CalendarUtil { * @param utcString UTC时间 * @return 日期对象 * @since 4.1.14 + * @deprecated 方法歧义,带T的日期并不一定是UTC时间,请使用 {@link #parseISO8601(String)} */ + @Deprecated public static DateTime parseUTC(String utcString) { - if (utcString == null) { + return parseISO8601(utcString); + } + + /** + * 解析ISO8601时间,格式:
+ *
    + *
  1. yyyy-MM-dd'T'HH:mm:ss'Z'
  2. + *
  3. yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
  4. + *
  5. yyyy-MM-dd'T'HH:mm:ssZ
  6. + *
  7. yyyy-MM-dd'T'HH:mm:ss.SSSZ
  8. + *
  9. yyyy-MM-dd'T'HH:mm:ss+0800
  10. + *
  11. yyyy-MM-dd'T'HH:mm:ss+08:00
  12. + *
+ * + * @param iso8601String ISO8601时间 + * @return 日期对象 + * @since 5.8.34 + */ + public static DateTime parseISO8601(String iso8601String) { + if (iso8601String == null) { return null; } - final int length = utcString.length(); - if (StrUtil.contains(utcString, 'Z')) { + final int length = iso8601String.length(); + if (StrUtil.contains(iso8601String, 'Z')) { if (length == DatePattern.UTC_PATTERN.length() - 4) { // 格式类似:2018-09-13T05:34:31Z,-4表示减去4个单引号的长度 - return parse(utcString, DatePattern.UTC_FORMAT); + return parse(iso8601String, DatePattern.UTC_FORMAT); } final int patternLength = DatePattern.UTC_MS_PATTERN.length(); @@ -861,61 +882,61 @@ public class DateUtil extends CalendarUtil { // -4 ~ -6范围表示匹配毫秒1~3位的情况 if (length <= patternLength && length >= patternLength - 6) { // issue#I7H34N,支持最多6位毫秒 - return parse(utcString, DatePattern.UTC_MS_FORMAT); + return parse(iso8601String, DatePattern.UTC_MS_FORMAT); } - } else if (StrUtil.contains(utcString, '+')) { + } else if (StrUtil.contains(iso8601String, '+')) { // 去除类似2019-06-01T19:45:43 +08:00加号前的空格 - utcString = utcString.replace(" +", "+"); - final String zoneOffset = StrUtil.subAfter(utcString, '+', true); + iso8601String = iso8601String.replace(" +", "+"); + final String zoneOffset = StrUtil.subAfter(iso8601String, '+', true); if (StrUtil.isBlank(zoneOffset)) { - throw new DateException("Invalid format: [{}]", utcString); + throw new DateException("Invalid format: [{}]", iso8601String); } if (false == StrUtil.contains(zoneOffset, ':')) { // +0800转换为+08:00 - final String pre = StrUtil.subBefore(utcString, '+', true); - utcString = pre + "+" + zoneOffset.substring(0, 2) + ":" + "00"; + final String pre = StrUtil.subBefore(iso8601String, '+', true); + iso8601String = pre + "+" + zoneOffset.substring(0, 2) + ":" + "00"; } - if (StrUtil.contains(utcString, CharUtil.DOT)) { + if (StrUtil.contains(iso8601String, CharUtil.DOT)) { // 带毫秒,格式类似:2018-09-13T05:34:31.999+08:00 - utcString = normalizeMillSeconds(utcString, ".", "+"); - return parse(utcString, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); + iso8601String = normalizeMillSeconds(iso8601String, ".", "+"); + return parse(iso8601String, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); } else { // 格式类似:2018-09-13T05:34:31+08:00 - return parse(utcString, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); + return parse(iso8601String, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); } - } else if(ReUtil.contains("-\\d{2}:?00", utcString)){ + } else if(ReUtil.contains("-\\d{2}:?00", iso8601String)){ // Issue#2612,类似 2022-09-14T23:59:00-08:00 或者 2022-09-14T23:59:00-0800 // 去除类似2019-06-01T19:45:43 -08:00加号前的空格 - utcString = utcString.replace(" -", "-"); - if(':' != utcString.charAt(utcString.length() - 3)){ - utcString = utcString.substring(0, utcString.length() - 2) + ":00"; + iso8601String = iso8601String.replace(" -", "-"); + if(':' != iso8601String.charAt(iso8601String.length() - 3)){ + iso8601String = iso8601String.substring(0, iso8601String.length() - 2) + ":00"; } - if (StrUtil.contains(utcString, CharUtil.DOT)) { + if (StrUtil.contains(iso8601String, CharUtil.DOT)) { // 带毫秒,格式类似:2018-09-13T05:34:31.999-08:00 - utcString = normalizeMillSeconds(utcString, ".", "-"); - return new DateTime(utcString, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); + iso8601String = normalizeMillSeconds(iso8601String, ".", "-"); + return new DateTime(iso8601String, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT); } else { // 格式类似:2018-09-13T05:34:31-08:00 - return new DateTime(utcString, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); + return new DateTime(iso8601String, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT); } } else { if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) { // 格式类似:2018-09-13T05:34:31 - return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT); + return parse(iso8601String, DatePattern.UTC_SIMPLE_FORMAT); } else if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 5) { // 格式类似:2018-09-13T05:34 - return parse(utcString + ":00", DatePattern.UTC_SIMPLE_FORMAT); - } else if (StrUtil.contains(utcString, CharUtil.DOT)) { + return parse(iso8601String + ":00", DatePattern.UTC_SIMPLE_FORMAT); + } else if (StrUtil.contains(iso8601String, CharUtil.DOT)) { // 可能为: 2021-03-17T06:31:33.99 - utcString = normalizeMillSeconds(utcString, ".", null); - return parse(utcString, DatePattern.UTC_SIMPLE_MS_FORMAT); + iso8601String = normalizeMillSeconds(iso8601String, ".", null); + return parse(iso8601String, DatePattern.UTC_SIMPLE_MS_FORMAT); } } // 没有更多匹配的时间格式 - throw new DateException("No format fit for date String [{}] !", utcString); + throw new DateException("No format fit for date String [{}] !", iso8601String); } /** @@ -1025,8 +1046,8 @@ public class DateUtil extends CalendarUtil { // Wed Aug 01 00:00:00 CST 2012 return parseRFC2822(dateStr); } else if (StrUtil.contains(dateStr, 'T')) { - // UTC时间 - return parseUTC(dateStr); + // ISO8601时间 + return parseISO8601(dateStr); } //标准日期格式(包括单个数字的日期时间) diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 3a535a7c9..d8cd91198 100755 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -605,9 +605,9 @@ public class DateUtilTest { } @Test - public void parseUTCTest() { + public void parseISO8601Test() { String dateStr1 = "2018-09-13T05:34:31Z"; - DateTime dt = DateUtil.parseUTC(dateStr1); + DateTime dt = DateUtil.parseISO8601(dateStr1); // parse方法支持UTC格式测试 final DateTime dt2 = DateUtil.parse(dateStr1); @@ -622,12 +622,12 @@ public class DateUtilTest { assertEquals("2018-09-13 13:34:31", dateStr); dateStr1 = "2018-09-13T13:34:32+0800"; - dt = DateUtil.parseUTC(dateStr1); + dt = DateUtil.parseISO8601(dateStr1); dateStr = dt.toString(TimeZone.getTimeZone("GMT+8:00")); assertEquals("2018-09-13 13:34:32", dateStr); dateStr1 = "2018-09-13T13:34:33+08:00"; - dt = DateUtil.parseUTC(dateStr1); + dt = DateUtil.parseISO8601(dateStr1); dateStr = dt.toString(TimeZone.getTimeZone("GMT+8:00")); assertEquals("2018-09-13 13:34:33", dateStr); @@ -644,14 +644,14 @@ public class DateUtilTest { assertEquals("2018-09-13 13:34:35", dateStr); dateStr1 = "2018-09-13T13:34:36.999+0800"; - dt = DateUtil.parseUTC(dateStr1); + dt = DateUtil.parseISO8601(dateStr1); final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_MS_PATTERN); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); dateStr = dt.toString(simpleDateFormat); assertEquals("2018-09-13 13:34:36.999", dateStr); dateStr1 = "2018-09-13T13:34:37.999+08:00"; - dt = DateUtil.parseUTC(dateStr1); + dt = DateUtil.parseISO8601(dateStr1); dateStr = dt.toString(simpleDateFormat); assertEquals("2018-09-13 13:34:37.999", dateStr); @@ -676,19 +676,19 @@ public class DateUtilTest { } @Test - public void parseUTCTest2() { + public void parseUTCTest() { // issue1503@Github // 检查不同毫秒长度都可以正常匹配 String utcTime = "2021-03-30T12:56:51.3Z"; - DateTime parse = DateUtil.parseUTC(utcTime); + DateTime parse = DateUtil.parseISO8601(utcTime); assertEquals("2021-03-30 12:56:51", parse.toString()); utcTime = "2021-03-30T12:56:51.34Z"; - parse = DateUtil.parseUTC(utcTime); + parse = DateUtil.parseISO8601(utcTime); assertEquals("2021-03-30 12:56:51", parse.toString()); utcTime = "2021-03-30T12:56:51.345Z"; - parse = DateUtil.parseUTC(utcTime); + parse = DateUtil.parseISO8601(utcTime); assertEquals("2021-03-30 12:56:51", parse.toString()); } @@ -994,7 +994,7 @@ public class DateUtilTest { @SuppressWarnings("ConstantConditions") @Test - public void parseISO8601Test() { + public void parseWithMilsTest() { final String dt = "2020-06-03 12:32:12,333"; final DateTime parse = DateUtil.parse(dt); assertEquals("2020-06-03 12:32:12", parse.toString()); diff --git a/hutool-core/src/test/java/cn/hutool/core/date/IssueIB9NPUTest.java b/hutool-core/src/test/java/cn/hutool/core/date/IssueIB9NPUTest.java new file mode 100644 index 000000000..447f5b1aa --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/IssueIB9NPUTest.java @@ -0,0 +1,12 @@ +package cn.hutool.core.date; + +import org.junit.jupiter.api.Test; + +import java.text.SimpleDateFormat; + +public class IssueIB9NPUTest { + @Test + void parseTest() { + DateUtil.parse("202409032400", new SimpleDateFormat("yyyyMMddHHmm")); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/date/IssueIBB6I5Test.java b/hutool-core/src/test/java/cn/hutool/core/date/IssueIBB6I5Test.java new file mode 100644 index 000000000..718f37a9f --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/date/IssueIBB6I5Test.java @@ -0,0 +1,25 @@ +package cn.hutool.core.date; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.ZoneId; +import java.util.TimeZone; + +public class IssueIBB6I5Test { + @Test + void parseISO8601Test() { + DateTime date = DateUtil.parseISO8601("2024-12-13T08:02:27Z"); + TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")); + date.setTimeZone(timeZone); + Assertions.assertEquals("2024-12-13 16:02:27", date.toString()); + } + + @Test + void parseISO8601Test2() { + DateTime date = DateUtil.parseISO8601("2024-12-13T08:02:27"); + TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")); + date.setTimeZone(timeZone); + Assertions.assertEquals("2024-12-13 08:02:27", date.toString()); + } +}