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时间,格式:
+ *
+ * - yyyy-MM-dd'T'HH:mm:ss'Z'
+ * - yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
+ * - yyyy-MM-dd'T'HH:mm:ssZ
+ * - yyyy-MM-dd'T'HH:mm:ss.SSSZ
+ * - yyyy-MM-dd'T'HH:mm:ss+0800
+ * - yyyy-MM-dd'T'HH:mm:ss+08:00
+ *
+ *
+ * @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());
+ }
+}