diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBuilder.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBuilder.java
index 3ba56c284..f2f0cc663 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBuilder.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBuilder.java
@@ -14,7 +14,6 @@ package org.dromara.hutool.core.date;
import java.time.*;
import java.util.Calendar;
-import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@@ -402,42 +401,23 @@ public final class DateBuilder {
return this;
}
- /**
- * 将当前时间对象转换为{@link Date}类型。此方法根据是否设置了时区偏移量使用不同的转换策略。
- *
* - yyyy-MM-dd HH:mm:ss
* - yyyy/MM/dd HH:mm:ss
@@ -830,7 +833,7 @@ public class DateUtil extends CalendarUtil {
* @return 日期
*/
public static DateTime parse(final CharSequence dateCharSequence) {
- if(TimeParser.INSTANCE.test(dateCharSequence)){
+ if (TimeParser.INSTANCE.test(dateCharSequence)) {
// 独立解析时间,则默认使用今天的日期
return TimeParser.INSTANCE.parse(dateCharSequence);
}
@@ -1709,6 +1712,7 @@ public class DateUtil extends CalendarUtil {
}
// region ----- range
+
/**
* 创建日期范围生成器
*
@@ -2071,70 +2075,4 @@ public class DateUtil extends CalendarUtil {
public static int getLastDayOfMonth(final Date date) {
return date(date).getLastDayOfMonth();
}
-
- // ------------------------------------------------------------------------ Private method start
-
- /**
- * 标准化日期,默认处理以空格区分的日期时间格式,空格前为日期,空格后为时间:
- * 将以下字符替换为"-"
- *
- *
- * "."
- * "/"
- * "年"
- * "月"
- *
- *
- * 将以下字符去除
- *
- *
- * "日"
- *
- *
- * 将以下字符替换为":"
- *
- *
- * "时"
- * "分"
- * "秒"
- *
- *
- * 当末位是":"时去除之(不存在毫秒时)
- *
- * @param dateStr 日期时间字符串
- * @return 格式化后的日期字符串
- */
- private static String normalize(final CharSequence dateStr) {
- if (StrUtil.isBlank(dateStr)) {
- return StrUtil.str(dateStr);
- }
-
- // 日期时间分开处理
- final List dateAndTime = SplitUtil.splitTrim(dateStr, StrUtil.SPACE);
- final int size = dateAndTime.size();
- if (size < 1 || size > 2) {
- // 非可被标准处理的格式
- return StrUtil.str(dateStr);
- }
-
- final StringBuilder builder = StrUtil.builder();
-
- // 日期部分("\"、"/"、"."、"年"、"月"都替换为"-")
- String datePart = dateAndTime.get(0).replaceAll("[/.年月]", "-");
- datePart = StrUtil.removeSuffix(datePart, "日");
- builder.append(datePart);
-
- // 时间部分
- if (size == 2) {
- builder.append(' ');
- String timePart = dateAndTime.get(1).replaceAll("[时分秒]", ":");
- timePart = StrUtil.removeSuffix(timePart, ":");
- //将ISO8601中的逗号替换为.
- timePart = timePart.replace(',', '.');
- builder.append(timePart);
- }
-
- return builder.toString();
- }
- // ------------------------------------------------------------------------ Private method end
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/Month.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/Month.java
index e6cbda417..79204840e 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/Month.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/Month.java
@@ -187,7 +187,7 @@ public enum Month {
* @since 5.8.0
*/
public static Month of(final String name) throws IllegalArgumentException {
- if (null != name && name.length() > 2) {
+ if (null != name && name.length() > 1) {
switch (Character.toLowerCase(name.charAt(0))) {
case 'a':
switch (Character.toLowerCase(name.charAt(1))) {
@@ -226,6 +226,32 @@ public enum Month {
return NOVEMBER; // november
case 'd':
return DECEMBER; // december
+ case '一':
+ return JANUARY;
+ case '二':
+ return FEBRUARY;
+ case '三':
+ return MARCH;
+ case '四':
+ return APRIL;
+ case '五':
+ return MAY;
+ case '六':
+ return JUNE;
+ case '七':
+ return JULY;
+ case '八':
+ return AUGUST;
+ case '九':
+ return SEPTEMBER;
+ case '十':
+ switch (Character.toLowerCase(name.charAt(1))){
+ case '一':
+ return NOVEMBER;
+ case '二':
+ return DECEMBER;
+ }
+ return OCTOBER;
}
}
@@ -234,11 +260,12 @@ public enum Month {
/**
* {@link java.time.Month}转换为Month对象
+ *
* @param month {@link java.time.Month}
* @return Month
* @since 5.8.0
*/
- public static Month of(final java.time.Month month){
+ public static Month of(final java.time.Month month) {
return of(month.ordinal());
}
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 3819688dd..7aef58fd5 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
@@ -28,7 +28,11 @@ import java.util.TimeZone;
import java.util.function.Function;
/**
- * JDK8+中的{@link java.time} 工具类封装
+ * JDK8+中的{@link java.time} 工具类封装
+ *
+ *
+ * - {@link LocalDateTime}表示一个本地时间,他始终表示当前时区的时间。
+ *
*
* @author looly
* @see DateUtil java7及其以下版本,使用Date工具类
@@ -55,7 +59,8 @@ public class TimeUtil extends TemporalAccessorUtil {
}
/**
- * {@link Instant}转{@link LocalDateTime},使用UTC时区
+ * {@link Instant}转{@link LocalDateTime},使用UTC时区
+ * 此方法自动将一个UTC时间转换为本地时间,如传入00:00,则结果为08:00
*
* @param instant {@link Instant}
* @return {@link LocalDateTime}
@@ -65,10 +70,12 @@ public class TimeUtil extends TemporalAccessorUtil {
}
/**
- * {@link Instant}转{@link LocalDateTime}
+ * {@link Instant}转{@link LocalDateTime}
+ * instant是一个无时区的时间戳,在转换为本地时间时,需指定这个时间戳所在时区
+ * 如果所在时区与当前时区不同,会转换时间
*
* @param instant {@link Instant}
- * @param zoneId 时区
+ * @param zoneId 时区,如果给定的时区与当前时区不同,会转换时间
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(final Instant instant, final ZoneId zoneId) {
@@ -80,10 +87,12 @@ public class TimeUtil extends TemporalAccessorUtil {
}
/**
- * {@link Instant}转{@link LocalDateTime}
+ * {@link Instant}转{@link LocalDateTime}
+ * instant是一个无时区的时间戳,在转换为本地时间时,需指定这个时间戳所在时区
+ * 如果所在时区与当前时区不同,会转换时间
*
* @param instant {@link Instant}
- * @param timeZone 时区
+ * @param timeZone 时区,如果给定的时区与当前时区不同,会转换时间
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(final Instant instant, final TimeZone timeZone) {
@@ -139,7 +148,8 @@ public class TimeUtil extends TemporalAccessorUtil {
}
/**
- * {@link Date}转{@link LocalDateTime},使用默认时区
+ * {@link Date}转{@link LocalDateTime},使用默认时区
+ * 如果为{@link DateTime}且提供了时区信息,则按照给定的时区转换为默认时区
*
* @param date Date对象
* @return {@link LocalDateTime}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/ZoneUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/ZoneUtil.java
index 68135bd5d..d49220779 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/ZoneUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/ZoneUtil.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.core.date;
import org.dromara.hutool.core.array.ArrayUtil;
+import org.dromara.hutool.core.util.ObjUtil;
import java.time.ZoneId;
import java.util.TimeZone;
@@ -80,10 +81,11 @@ public class ZoneUtil {
*
* @param rawOffset 偏移量
* @param timeUnit 偏移量单位
- * @return 时区ID
+ * @return 时区ID,未找到返回{@link null}
*/
public static String getAvailableID(final int rawOffset, final TimeUnit timeUnit) {
- final String[] availableIDs = TimeZone.getAvailableIDs((int) timeUnit.toMillis(rawOffset));
+ final String[] availableIDs = TimeZone.getAvailableIDs(
+ (int) ObjUtil.defaultIfNull(timeUnit, TimeUnit.MILLISECONDS).toMillis(rawOffset));
return ArrayUtil.isEmpty(availableIDs) ? null : availableIDs[0];
}
}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParser.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParser.java
index 2c4ae3f42..cf67e340c 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParser.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParser.java
@@ -31,12 +31,12 @@ public class GlobalRegexDateParser {
final String yearRegex = "(?\\d{2,4})";
// 月的正则,匹配:Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec,
// 或 January, February, March, April, May, June, July, August, September, October, November, December
- final String monthRegex = "(?[jfmaasond][aepucoe][nbrylgptvc]\\w{0,6})";
+ final String monthRegex = "(?[jfmaasond][aepucoe][nbrylgptvc]\\w{0,6}|[一二三四五六七八九十]{1,2}月)";
final String dayRegex = "(?\\d{1,2})(?:th)?";
// 周的正则,匹配:Mon, Tue, Wed, Thu, Fri, Sat, Sun,
// 或 Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
// 周一般出现在日期头部,可选
- final String weekRegexWithSuff = "(?[mwfts][oeruha][ndieut](\\w{3,6})?\\W+)?";
+ final String weekRegexWithSuff = "((?[mwfts][oeruha][ndieut](\\w{3,6})?|(星期|周)[一二三四五六日])\\W+)?";
// hh:mm:ss.SSSSZ hh:mm:ss.SSSS hh:mm:ss hh:mm
final String timeRegexWithPre = "(" +
"(\\W+|T)(at\\s)?(?\\d{1,2})" +
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/RegexDateParser.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/RegexDateParser.java
index fd34a16d2..978e504bd 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/RegexDateParser.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/format/parser/RegexDateParser.java
@@ -25,6 +25,8 @@ import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.dfa.WordTree;
import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -115,7 +117,31 @@ public class RegexDateParser implements DateParser, Serializable {
@Override
public Date parse(final CharSequence source) throws DateException {
Assert.notBlank(source, "Date str must be not blank!");
- return parseToBuilder(source).toDateTime();
+ return parseToBuilder(source).toDate();
+ }
+
+ /**
+ * 解析日期,结果为{@link LocalDateTime}
+ *
+ * @param source 日期字符串
+ * @return {@link LocalDateTime}
+ * @throws DateException 解析异常
+ */
+ public LocalDateTime parseToLocalDateTime(final CharSequence source) throws DateException {
+ Assert.notBlank(source, "Date str must be not blank!");
+ return parseToBuilder(source).toLocalDateTime();
+ }
+
+ /**
+ * 解析日期,结果为{@link OffsetDateTime}
+ *
+ * @param source 日期字符串
+ * @return {@link OffsetDateTime}
+ * @throws DateException 解析异常
+ */
+ public OffsetDateTime parseToOffsetDateTime(final CharSequence source) throws DateException {
+ Assert.notBlank(source, "Date str must be not blank!");
+ return parseToBuilder(source).toOffsetDateTime();
}
/**
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/CalendarUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/CalendarUtilTest.java
index d335bbdda..97072f40b 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/CalendarUtilTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/CalendarUtilTest.java
@@ -12,6 +12,7 @@
package org.dromara.hutool.core.date;
+import org.dromara.hutool.core.lang.Console;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -40,4 +41,16 @@ public class CalendarUtilTest {
DateUtil.date(calendar);
});
}
+
+ @Test
+ void setTimeZoneTest() {
+ // Calendar中,设置时区并不会变化时间戳
+ final Calendar instance = Calendar.getInstance();
+ Console.log(instance.getTimeInMillis());
+ final long timeInMillis = instance.getTimeInMillis();
+ instance.setTimeZone(ZoneUtil.ZONE_UTC);
+ final long timeInMillis2 = instance.getTimeInMillis();
+
+ Assertions.assertEquals(timeInMillis, timeInMillis2);
+ }
}
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/DateBuilderTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/DateBuilderTest.java
index 480d96b74..3d3ec3d23 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/DateBuilderTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/DateBuilderTest.java
@@ -16,7 +16,7 @@ public class DateBuilderTest {
builder.setDay(1);
final Date date = builder.toDate();
- Assertions.assertEquals("2019-10-01", DateUtil.date(date).toDateStr());
+ Assertions.assertEquals("2019-10-01 00:00:00", date.toString());
}
@Test
@@ -32,7 +32,7 @@ public class DateBuilderTest {
.setZone(TimeZone.getDefault());
final LocalDateTime dateTime = builder.toLocalDateTime();
- Assertions.assertEquals("2019-10-01T10:20:30.900", builder.toLocalDateTime().toString());
+ Assertions.assertEquals("2019-10-01T10:20:30.900", dateTime.toString());
}
@Test
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/DateTimeTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/DateTimeTest.java
index 047137ced..8243e1e5f 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/DateTimeTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/DateTimeTest.java
@@ -15,6 +15,8 @@ package org.dromara.hutool.core.date;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.TimeZone;
+
/**
* DateTime单元测试
*
@@ -128,6 +130,17 @@ public class DateTimeTest {
Assertions.assertEquals("2017-01-05T12:34:23+08:00", dateStr);
}
+ @Test
+ public void toStringWithTimeZoneTest() {
+ final DateTime dateTime = new DateTime("2017-01-05 12:34:23", DatePattern.NORM_DATETIME_FORMAT);
+
+ final String dateStr = dateTime.toString(TimeZone.getTimeZone("UTC"));
+ Assertions.assertEquals("2017-01-05 04:34:23", dateStr);
+
+ dateTime.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Assertions.assertEquals("2017-01-05 04:34:23", dateTime.toString());
+ }
+
@Test
public void monthTest() {
//noinspection ConstantConditions
@@ -138,7 +151,7 @@ public class DateTimeTest {
@Test
public void weekOfYearTest() {
final DateTime date = DateUtil.date(DateUtil.parse("2016-12-27"));
- //noinspection ConstantConditions
+
Assertions.assertEquals(2016, date.year());
//跨年的周返回的总是1
Assertions.assertEquals(1, date.weekOfYear());
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/IssueI9C2D4Test.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/IssueI9C2D4Test.java
index e0d4c647e..41ed6f5cf 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/IssueI9C2D4Test.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/IssueI9C2D4Test.java
@@ -18,7 +18,7 @@ public class IssueI9C2D4Test {
public void parseHttpTest2() {
final String dateStr = "星期四, 28 三月 2024 14:33:49 GMT";
final Date parse = DateUtil.parse(dateStr);
- Assertions.assertEquals("2024-03-28 14:33:49", Objects.requireNonNull(parse).toString());
+ Assertions.assertEquals("2024-03-28 22:33:49", Objects.requireNonNull(parse).toString());
}
@Test
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/MonthTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/MonthTest.java
index ad1e423ce..49466dd35 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/MonthTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/MonthTest.java
@@ -77,5 +77,14 @@ public class MonthTest {
month = Month.of(java.time.Month.FEBRUARY);
Assertions.assertEquals(Month.FEBRUARY, month);
+
+ month = Month.of("二月");
+ Assertions.assertEquals(Month.FEBRUARY, month);
+ month = Month.of("十月");
+ Assertions.assertEquals(Month.OCTOBER, month);
+ month = Month.of("十一月");
+ Assertions.assertEquals(Month.NOVEMBER, month);
+ month = Month.of("十二月");
+ Assertions.assertEquals(Month.DECEMBER, month);
}
}
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/TimeUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/TimeUtilTest.java
index d1545447f..c1db57210 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/TimeUtilTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/TimeUtilTest.java
@@ -19,7 +19,6 @@ import org.junit.jupiter.api.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
-import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -37,7 +36,8 @@ public class TimeUtilTest {
@Test
public void ofTest() {
final String dateStr = "2020-01-23T12:23:56";
- final Date dt = DateUtil.parse(dateStr);
+ final DateTime dt = DateUtil.parse(dateStr);
+ Console.log(dt.getTimeZone());
final LocalDateTime of = TimeUtil.of(dt);
Assertions.assertNotNull(of);
@@ -47,9 +47,10 @@ public class TimeUtilTest {
@Test
public void ofUTCTest() {
final String dateStr = "2020-01-23T12:23:56Z";
- final Date dt = DateUtil.parse(dateStr);
+ // 因为`Z`位于末尾,表示为UTC时间,parse后会自动转换为本地时间
+ final DateTime dt = DateUtil.parse(dateStr);
- final LocalDateTime of = TimeUtil.of(dt);
+ final LocalDateTime of = TimeUtil.of(dt.setTimeZone(ZoneUtil.ZONE_UTC));
final LocalDateTime of2 = TimeUtil.ofUTC(dt.getTime());
Assertions.assertNotNull(of);
Assertions.assertNotNull(of2);
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/ZoneUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/ZoneUtilTest.java
index 9d43dd5c9..9d21ff6f5 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/ZoneUtilTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/ZoneUtilTest.java
@@ -19,7 +19,8 @@ import java.time.ZoneId;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class ZoneUtilTest {
@@ -55,21 +56,6 @@ public class ZoneUtilTest {
assertNull(result, "Expected null TimeZone for invalid offset");
}
- @Test
- public void testGetTimeZoneByOffsetWithNullTimeUnitThrowsException() {
- // Arrange
- final int rawOffset = 8;
- final TimeUnit timeUnit = null; // Null unit to simulate error condition
-
- // Act & Assert
- final NullPointerException thrown = assertThrows(
- NullPointerException.class,
- () -> ZoneUtil.getTimeZoneByOffset(rawOffset, timeUnit),
- "Expected NullPointerException for null TimeUnit"
- );
- assertTrue(thrown.getMessage().contains("timeUnit"), "Exception message should mention the null parameter");
- }
-
@Test
public void testGetAvailableIDWithInvalidOffset() {
// Test with an invalid offset that should result in null or an exception.
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParserTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParserTest.java
index d288f3050..2100bcb3e 100644
--- a/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParserTest.java
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/format/parser/GlobalRegexDateParserTest.java
@@ -63,6 +63,8 @@ public class GlobalRegexDateParserTest {
assertParse("2014-04-08 00:00:00", "2014年04月08日");
assertParse("2017-02-01 12:23:45", "2017年02月01日 12时23分45秒");
assertParse("2017-02-01 12:23:45", "2017年02月01日 12:23:45");
+ assertParse("2024-03-28 22:33:49", "星期四, 28 三月 2024 14:33:49 GMT");
+ assertParse("2024-03-28 22:33:49", "周四, 28 三月 2024 14:33:49 GMT");
}
@Test