diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec05bcc48..0f859e2cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
* 【core 】 增加JNDIUtil(issue#1727@Github)
* 【core 】 SpringUtil增加unregisterBean方法(pr#388@Gitee)
* 【core 】 优化TextSimilarity公共子串算法(issue#I42A6V@Gitee)
+* 【core 】 优化DateUtil.parse对UTC附带时区字符串解析(issue#I437AP@Gitee)
### 🐞Bug修复
* 【jwt 】 修复JWTUtil中几个方法非static的问题(issue#1735@Github)
diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java
index 8feeac0ce..4107fb2a8 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/DatePattern.java
@@ -267,6 +267,15 @@ public class DatePattern {
*/
public static final FastDateFormat UTC_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_WITH_ZONE_OFFSET_PATTERN, TimeZone.getTimeZone("UTC"));
+ /**
+ * UTC时间:yyyy-MM-dd'T'HH:mm:ssXXX
+ */
+ public static final String UTC_WITH_XXX_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
+ /**
+ * UTC时间{@link FastDateFormat}:yyyy-MM-dd'T'HH:mm:ssXXX
+ */
+ public static final FastDateFormat UTC_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_WITH_XXX_OFFSET_PATTERN);
+
/**
* UTC时间:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
*/
@@ -285,6 +294,15 @@ public class DatePattern {
*/
public static final FastDateFormat UTC_MS_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_MS_WITH_ZONE_OFFSET_PATTERN, TimeZone.getTimeZone("UTC"));
+ /**
+ * UTC时间:yyyy-MM-dd'T'HH:mm:ss.SSSXXX
+ */
+ public static final String UTC_MS_WITH_XXX_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
+ /**
+ * UTC时间{@link FastDateFormat}:yyyy-MM-dd'T'HH:mm:ss.SSSXXX
+ */
+ public static final FastDateFormat UTC_MS_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_MS_WITH_XXX_OFFSET_PATTERN);
+
/**
* 创建并为 {@link DateTimeFormatter} 赋予默认时区和位置信息,默认值为系统默认值。
*
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 7cbe2f836..865c27c6b 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java
@@ -809,6 +809,8 @@ public class DateUtil extends CalendarUtil {
*
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 utcString UTC时间
@@ -832,14 +834,28 @@ public class DateUtil extends CalendarUtil {
if (length <= patternLength - 4 && length >= patternLength - 6) {
return parse(utcString, DatePattern.UTC_MS_FORMAT);
}
+ } else if(StrUtil.contains(utcString, '+')){
+ // 去除类似2019-06-01T19:45:43 +08:00加号前的空格
+ utcString = utcString.replace(" +", "+");
+ final String zoneOffset = StrUtil.subAfter(utcString, '+', true);
+ if(StrUtil.isBlank(zoneOffset)){
+ throw new DateException("Invalid format: [{}]", utcString);
+ }
+ if(false == StrUtil.contains(zoneOffset, ':')){
+ // +0800转换为+08:00
+ final String pre = StrUtil.subBefore(utcString, '+', true);
+ utcString = pre + "+" + zoneOffset.substring(0, 2) + ":" + "00";
+ }
+
+ if(StrUtil.contains(utcString, CharUtil.DOT)) {
+ // 带毫秒,格式类似:2018-09-13T05:34:31.999+08:00
+ return parse(utcString, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT);
+ } else {
+ // 格式类似:2018-09-13T05:34:31+08:00
+ return parse(utcString, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT);
+ }
} else {
- if (length == DatePattern.UTC_WITH_ZONE_OFFSET_PATTERN.length() + 2 || length == DatePattern.UTC_WITH_ZONE_OFFSET_PATTERN.length() + 3) {
- // 格式类似:2018-09-13T05:34:31+0800 或 2018-09-13T05:34:31+08:00
- return parse(utcString, DatePattern.UTC_WITH_ZONE_OFFSET_FORMAT);
- } else if (length == DatePattern.UTC_MS_WITH_ZONE_OFFSET_PATTERN.length() + 2 || length == DatePattern.UTC_MS_WITH_ZONE_OFFSET_PATTERN.length() + 3) {
- // 格式类似:2018-09-13T05:34:31.999+0800 或 2018-09-13T05:34:31.999+08:00
- return parse(utcString, DatePattern.UTC_MS_WITH_ZONE_OFFSET_FORMAT);
- } else if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) {
+ if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) {
// 格式类似:2018-09-13T05:34:31
return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT);
} else if (StrUtil.contains(utcString, CharUtil.DOT)) {
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 39d95cf71..79e9d638d 100644
--- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java
@@ -438,7 +438,13 @@ public class DateUtilTest {
@Test
public void parseTest7() {
String str = "2019-06-01T19:45:43.000 +0800";
- DateTime dateTime = DateUtil.parse(str, "yyyy-MM-dd'T'HH:mm:ss.SSS Z");
+ DateTime dateTime = DateUtil.parse(str);
+ assert dateTime != null;
+ Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString());
+
+ str = "2019-06-01T19:45:43 +08:00";
+ dateTime = DateUtil.parse(str);
+ assert dateTime != null;
Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString());
}
@@ -450,6 +456,20 @@ public class DateUtilTest {
Assert.assertEquals("2020-06-28 02:14:13", dateTime.toString());
}
+ @Test
+ public void parseUTCOffsetTest() {
+ // issue#I437AP@Gitee
+ String str = "2019-06-01T19:45:43+08:00";
+ DateTime dateTime = DateUtil.parse(str);
+ assert dateTime != null;
+ Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString());
+
+ str = "2019-06-01T19:45:43 +08:00";
+ dateTime = DateUtil.parse(str);
+ assert dateTime != null;
+ Assert.assertEquals("2019-06-01 19:45:43", dateTime.toString());
+ }
+
@Test
public void parseAndOffsetTest() {
// 检查UTC时间偏移是否准确
diff --git a/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java
index aa22faf78..0d3fa84a6 100644
--- a/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/date/LocalDateTimeUtilTest.java
@@ -29,6 +29,12 @@ public class LocalDateTimeUtilTest {
Assert.assertEquals(dateStr, of.toString());
}
+ @Test
+ public void parseOffsetTest() {
+ final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2021-07-30T16:27:27+08:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ Assert.assertEquals("2021-07-30T16:27:27", localDateTime.toString());
+ }
+
@Test
public void parseTest() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);
@@ -137,4 +143,4 @@ public class LocalDateTimeUtilTest {
final LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(localDateTime);
Assert.assertEquals("2020-01-23T23:59:59.999999999", endOfDay.toString());
}
-}
\ No newline at end of file
+}