This commit is contained in:
Looly 2023-03-14 20:26:26 +08:00
parent e4999ca6f6
commit 6cd802e9ac
10 changed files with 108 additions and 83 deletions

View File

@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* <li>yyyy-MM-dd HH:mm:ss.SSS 示例2022-08-05 12:59:59.559</li>
* <li>yyyy-MM-dd HH:mm:ss.SSSZ 示例2022-08-05 12:59:59.559+0800东八区中国时区2022-08-05 04:59:59.559+0000冰岛0时区, 年月日 时分秒 毫秒 时区</li>
* <li>yyyy-MM-dd HH:mm:ss.SSSz 示例2022-08-05 12:59:59.559UTC世界标准时间=0时区2022-08-05T12:59:59.599GMT冰岛0时区2022-08-05T12:59:59.599CST东八区中国时区2022-08-23T03:45:00.599EDT美国东北纽约时间-0400 ,年月日 时分秒 毫秒 时区</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSS'Z' 示例2022-08-05T12:59:59.559Z, 其中''单引号表示转义字符T:分隔符Z:一般UTC,0时区的时间含义</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSS'Z' 示例2022-08-05T12:59:59.559Z, 其中''单引号表示转义字符T:分隔符Z:一般UTC,0时区的时间含义</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSSZ 示例2022-08-05T11:59:59.559+0800, 其中Z,表示时区</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSSX 示例2022-08-05T12:59:59.559+08, 其中X:两位时区+08表示东8区中国时区</li>
* <li>yyyy-MM-dd'T'HH:mm:ss.SSSXX 示例2022-08-05T12:59:59.559+0800, 其中XX:四位时区</li>
@ -61,7 +61,7 @@ import java.util.regex.Pattern;
* 09:30 UTC表示为09:30ZT0930Z其中Z +00:00 的缩写意思是 UTC(零时分秒的偏移量).
* </p>
* <ul>
* <li>yyyy-MM-dd'T'HH:mm:ssZ</li>
* <li>yyyy-MM-dd'T'HH:mm:ss'Z'</li>
* <li>2022-08-23T15:20:46UTC</li>
* <li>2022-08-23T15:20:46 UTC</li>
* <li>2022-08-23T15:20:46+0000</li>
@ -189,15 +189,15 @@ public class DatePattern {
/**
* ISO8601日期时间格式精确到毫秒yyyy-MM-dd HH:mm:ss,SSS
*/
public static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
public static final String NORM_DATETIME_COMMA_MS_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
/**
* ISO8601日期时间格式精确到毫秒 {@link FastDateFormat}yyyy-MM-dd HH:mm:ss,SSS
*/
public static final FastDateFormat ISO8601_FORMAT = FastDateFormat.getInstance(ISO8601_PATTERN);
public static final FastDateFormat NORM_DATETIME_COMMA_MS_FORMAT = FastDateFormat.getInstance(NORM_DATETIME_COMMA_MS_PATTERN);
/**
* 标准日期格式 {@link DateTimeFormatter}yyyy-MM-dd HH:mm:ss,SSS
*/
public static final DateTimeFormatter ISO8601_FORMATTER = createFormatter(ISO8601_PATTERN);
public static final DateTimeFormatter NORM_DATETIME_COMMA_MS_FORMATTER = createFormatter(NORM_DATETIME_COMMA_MS_PATTERN);
/**
* 标准日期格式yyyy年MM月dd日
@ -286,8 +286,7 @@ public class DatePattern {
.toFormatter();
// endregion
// region Others
//================================================== Others ==================================================
// region ----- Others
/**
* HTTP头中日期时间格式EEE, dd MMM yyyy HH:mm:ss z
*/
@ -307,76 +306,78 @@ public class DatePattern {
public static final FastDateFormat JDK_DATETIME_FORMAT = FastDateFormat.getInstance(JDK_DATETIME_PATTERN, Locale.US);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss
* ISO8601日期时间yyyy-MM-dd'T'HH:mm:ss<br>
* 按照ISO8601规范默认使用T分隔日期和时间末尾不加Z表示当地时区
*/
public static final String UTC_SIMPLE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
public static final String ISO8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss
* ISO8601日期时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss
*/
public static final FastDateFormat UTC_SIMPLE_FORMAT = FastDateFormat.getInstance(UTC_SIMPLE_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat ISO8601_FORMAT = FastDateFormat.getInstance(ISO8601_PATTERN);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss.SSS
*/
public static final String UTC_SIMPLE_MS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
public static final String ISO8601_MS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss.SSS
*/
public static final FastDateFormat UTC_SIMPLE_MS_FORMAT = FastDateFormat.getInstance(UTC_SIMPLE_MS_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat ISO8601_MS_FORMAT = FastDateFormat.getInstance(ISO8601_MS_PATTERN);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss'Z'
* UTC时间yyyy-MM-dd'T'HH:mm:ss'Z'<br>
* 按照ISO8601规范后缀加Z表示UTC时间
*/
public static final String UTC_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss'Z'
* ISO8601时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss'Z'
*/
public static final FastDateFormat UTC_FORMAT = FastDateFormat.getInstance(UTC_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat UTC_FORMAT = FastDateFormat.getInstance(UTC_PATTERN, ZoneUtil.ZONE_UTC);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ssZ
* ISO8601时间yyyy-MM-dd'T'HH:mm:ssZZ表示一个时间偏移+0800
*/
public static final String UTC_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
public static final String ISO8601_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ssZ
* ISO8601时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ssZZ表示一个时间偏移+0800
*/
public static final FastDateFormat UTC_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_WITH_ZONE_OFFSET_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat ISO8601_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(ISO8601_WITH_ZONE_OFFSET_PATTERN);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ssXXX
* ISO8601时间yyyy-MM-dd'T'HH:mm:ssXXX
*/
public static final String UTC_WITH_XXX_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
public static final String ISO8601_WITH_XXX_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ssXXX";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ssXXX
* ISO8601时间{@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);
public static final FastDateFormat ISO8601_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(ISO8601_WITH_XXX_OFFSET_PATTERN);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
* ISO8601时间yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
*/
public static final String UTC_MS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
* ISO8601时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
*/
public static final FastDateFormat UTC_MS_FORMAT = FastDateFormat.getInstance(UTC_MS_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat UTC_MS_FORMAT = FastDateFormat.getInstance(UTC_MS_PATTERN, ZoneUtil.ZONE_UTC);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss.SSSZ
* ISO8601时间yyyy-MM-dd'T'HH:mm:ss.SSSZ
*/
public static final String UTC_MS_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
public static final String ISO8601_MS_WITH_ZONE_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss.SSSZ
* ISO8601时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss.SSSZ
*/
public static final FastDateFormat UTC_MS_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_MS_WITH_ZONE_OFFSET_PATTERN, TimeZone.getTimeZone("UTC"));
public static final FastDateFormat ISO8601_MS_WITH_ZONE_OFFSET_FORMAT = FastDateFormat.getInstance(ISO8601_MS_WITH_ZONE_OFFSET_PATTERN);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss.SSSXXX
* ISO8601时间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";
public static final String ISO8601_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);
public static final FastDateFormat ISO8601_MS_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(ISO8601_MS_WITH_XXX_OFFSET_PATTERN);
// endregion
/**

View File

@ -23,11 +23,6 @@ import java.util.function.Function;
* @since 6.0.0
*/
public class TimeUtil extends TemporalAccessorUtil {
/**
* UTC ZoneID
*/
public static final ZoneId ZONE_ID_UTC = ZoneId.of("UTC");
/**
* 当前时间默认时区
*
@ -53,7 +48,7 @@ public class TimeUtil extends TemporalAccessorUtil {
* @return {@link LocalDateTime}
*/
public static LocalDateTime ofUTC(final Instant instant) {
return of(instant, ZONE_ID_UTC);
return of(instant, ZoneUtil.ZONE_ID_UTC);
}
/**

View File

@ -11,6 +11,15 @@ import java.util.TimeZone;
*/
public class ZoneUtil {
/**
* UTC ZoneID
*/
public static final TimeZone ZONE_UTC = TimeZone.getTimeZone("UTC");
/**
* UTC TimeZone
*/
public static final ZoneId ZONE_ID_UTC = ZONE_UTC.toZoneId();
/**
* {@link ZoneId}转换为{@link TimeZone}{@code null}则返回系统默认值
*

View File

@ -61,10 +61,10 @@ public class UTCDateParser extends DefaultDateBasic implements DateParser {
if (StrUtil.contains(source, CharUtil.DOT)) {
// 带毫秒格式类似2018-09-13T05:34:31.999+08:00
source = normalizeMillSeconds(source, ".", "+");
return new DateTime(source, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT);
return new DateTime(source, DatePattern.ISO8601_MS_WITH_XXX_OFFSET_FORMAT);
} else {
// 格式类似2018-09-13T05:34:31+08:00
return new DateTime(source, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT);
return new DateTime(source, DatePattern.ISO8601_WITH_XXX_OFFSET_FORMAT);
}
} else if(ReUtil.contains("-\\d{2}:?00", source)){
// Issue#2612类似 2022-09-14T23:59:00-08:00 或者 2022-09-14T23:59:00-0800
@ -78,22 +78,22 @@ public class UTCDateParser extends DefaultDateBasic implements DateParser {
if (StrUtil.contains(source, CharUtil.DOT)) {
// 带毫秒格式类似2018-09-13T05:34:31.999-08:00
source = normalizeMillSeconds(source, ".", "-");
return new DateTime(source, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT);
return new DateTime(source, DatePattern.ISO8601_MS_WITH_XXX_OFFSET_FORMAT);
} else {
// 格式类似2018-09-13T05:34:31-08:00
return new DateTime(source, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT);
return new DateTime(source, DatePattern.ISO8601_WITH_XXX_OFFSET_FORMAT);
}
} else {
if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) {
if (length == DatePattern.ISO8601_PATTERN.length() - 2) {
// 格式类似2018-09-13T05:34:31
return new DateTime(source, DatePattern.UTC_SIMPLE_FORMAT);
} else if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 5) {
return new DateTime(source, DatePattern.ISO8601_FORMAT);
} else if (length == DatePattern.ISO8601_PATTERN.length() - 5) {
// 格式类似2018-09-13T05:34
return new DateTime(source + ":00", DatePattern.UTC_SIMPLE_FORMAT);
return new DateTime(source + ":00", DatePattern.ISO8601_FORMAT);
} else if (StrUtil.contains(source, CharUtil.DOT)) {
// 可能为 2021-03-17T06:31:33.99
source = normalizeMillSeconds(source, ".", null);
return new DateTime(source, DatePattern.UTC_SIMPLE_MS_FORMAT);
return new DateTime(source, DatePattern.ISO8601_MS_FORMAT);
}
}
// 没有更多匹配的时间格式

View File

@ -1,5 +1,6 @@
package cn.hutool.core.text.split;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.regex.PatternPool;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.text.finder.CharFinder;
@ -302,7 +303,8 @@ public class SplitUtil {
/**
* 切分字符串<br>
* 如果为空字符串或者null 则返回空集合
* 如果提供的字符串为{@code null}则返回一个空的{@link ArrayList}<br>
* 如果提供的字符串为""则当ignoreEmpty时返回空的{@link ArrayList}否则返回只有一个""元素的{@link ArrayList}
*
* @param text 被切分的字符串
* @param separator 分隔符字符串
@ -314,8 +316,10 @@ public class SplitUtil {
* @since 3.2.1
*/
public static List<String> split(final CharSequence text, final String separator, final int limit, final boolean isTrim, final boolean ignoreEmpty, final boolean ignoreCase) {
if (StrUtil.isEmpty(text)) {
if(null == text){
return new ArrayList<>(0);
} else if (0 == text.length()) {
return ignoreEmpty ? new ArrayList<>(0) : ListUtil.of(StrUtil.EMPTY);
}
final SplitIter splitIter = new SplitIter(text, new StrFinder(separator, ignoreCase), limit, ignoreEmpty);
return splitIter.toList(isTrim);

View File

@ -109,10 +109,10 @@ public class DateTimeTest {
public void toStringTest2() {
final DateTime dateTime = new DateTime("2017-01-05 12:34:23", DatePattern.NORM_DATETIME_FORMAT);
String dateStr = dateTime.toString(DatePattern.UTC_WITH_ZONE_OFFSET_PATTERN);
String dateStr = dateTime.toString(DatePattern.ISO8601_WITH_ZONE_OFFSET_PATTERN);
Assert.assertEquals("2017-01-05T12:34:23+0800", dateStr);
dateStr = dateTime.toString(DatePattern.UTC_WITH_XXX_OFFSET_PATTERN);
dateStr = dateTime.toString(DatePattern.ISO8601_WITH_XXX_OFFSET_PATTERN);
Assert.assertEquals("2017-01-05T12:34:23+08:00", dateStr);
}

View File

@ -1,6 +1,5 @@
package cn.hutool.core.date;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.BetweenFormatter.Level;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Console;
@ -14,15 +13,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;
import java.util.*;
/**
* 时间工具单元测试<br>
@ -796,23 +787,6 @@ public class DateUtilTest {
Assert.assertEquals(0, DateUtil.compare(date11, date22, DatePattern.NORM_MONTH_PATTERN));
}
@Test
public void yearAndQTest() {
final String yearAndQuarter = DateUtil.yearAndQuarter(DateUtil.parse("2018-12-01"));
Assert.assertEquals("20184", yearAndQuarter);
final LinkedHashSet<String> yearAndQuarters = DateUtil.yearAndQuarter(DateUtil.parse("2018-09-10"), DateUtil.parse("2018-12-20"));
final List<String> list = ListUtil.of(false, yearAndQuarters);
Assert.assertEquals(2, list.size());
Assert.assertEquals("20183", list.get(0));
Assert.assertEquals("20184", list.get(1));
final LinkedHashSet<String> yearAndQuarters2 = DateUtil.yearAndQuarter(DateUtil.parse("2018-10-10"), DateUtil.parse("2018-12-10"));
final List<String> list2 = ListUtil.of(false, yearAndQuarters2);
Assert.assertEquals(1, list2.size());
Assert.assertEquals("20184", list2.get(0));
}
@Test
public void formatHttpDateTest() {
final String formatHttpDate = DateUtil.formatHttpDate(DateUtil.parse("2019-01-02 22:32:01"));

View File

@ -0,0 +1,22 @@
package cn.hutool.core.date;
import org.junit.Assert;
import org.junit.Test;
public class Issue2981Test {
/**
* https://github.com/dromara/hutool/issues/2981<br>
* 按照ISO8601规范以Z结尾表示UTC时间否则为当地时间
*/
@SuppressWarnings("DataFlowIssue")
@Test
public void parseUTCTest() {
final String str1 = "2019-01-01T00:00:00.000Z";
final String str2 = "2019-01-01T00:00:00.000";
final String str3 = "2019-01-01 00:00:00.000";
Assert.assertEquals(1546300800000L, DateUtil.parse(str1).getTime());
Assert.assertEquals(1546272000000L, DateUtil.parse(str2).getTime());
Assert.assertEquals(1546272000000L, DateUtil.parse(str3).getTime());
}
}

View File

@ -27,12 +27,22 @@ public class TimeUtilTest {
final String dateStr = "2020-01-23T12:23:56";
final DateTime dt = DateUtil.parse(dateStr);
LocalDateTime of = TimeUtil.of(dt);
final LocalDateTime of = TimeUtil.of(dt);
Assert.assertNotNull(of);
Assert.assertEquals(dateStr, of.toString());
}
of = TimeUtil.ofUTC(dt.getTime());
Assert.assertEquals(dateStr, of.toString());
@SuppressWarnings("DataFlowIssue")
@Test
public void ofUTCTest() {
final String dateStr = "2020-01-23T12:23:56Z";
final DateTime dt = DateUtil.parse(dateStr);
final LocalDateTime of = TimeUtil.of(dt);
final LocalDateTime of2 = TimeUtil.ofUTC(dt.getTime());
Assert.assertNotNull(of);
Assert.assertNotNull(of2);
Assert.assertEquals(of, of2);
}
@Test

View File

@ -1,5 +1,6 @@
package cn.hutool.core.text.split;
import cn.hutool.core.lang.Console;
import org.junit.Assert;
import org.junit.Test;
@ -59,16 +60,25 @@ public class StrSplitterTest {
final String str = "";
final String[] split = str.split(",");
final String[] strings = SplitUtil.splitToArray(str, ",", -1, false, false);
Assert.assertNotNull(strings);
Assert.assertArrayEquals(split, strings);
final String[] strings2 = SplitUtil.splitToArray(str, ",", -1, false, true);
Assert.assertEquals(0, strings2.length);
}
@SuppressWarnings("ConstantValue")
@Test
public void splitNullTest(){
final String str = null;
final String[] strings = SplitUtil.splitToArray(str, ",", -1, false, false);
Assert.assertNotNull(strings);
Assert.assertEquals(0, strings.length);
final String[] strings2 = SplitUtil.splitToArray(str, ",", -1, false, true);
Assert.assertNotNull(strings2);
Assert.assertEquals(0, strings2.length);
}
/**