mirror of
https://gitee.com/dromara/hutool.git
synced 2025-08-20 00:44:27 +08:00
Compare commits
8 Commits
b5ccc1a7c9
...
59f33fd12d
Author | SHA1 | Date | |
---|---|---|---|
![]() |
59f33fd12d | ||
![]() |
4dcbc74cd1 | ||
![]() |
6760658cba | ||
![]() |
0b71a19ba8 | ||
![]() |
cee0efdee1 | ||
![]() |
0661bf27df | ||
![]() |
cae1203591 | ||
![]() |
5244b7510e |
@ -2,12 +2,14 @@
|
||||
# 🚀Changelog
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.8.40(2025-07-24)
|
||||
# 5.8.40(2025-07-30)
|
||||
|
||||
### 🐣新特性
|
||||
* 【captcha】 `MathGenerator`四则运算方式支持不生成负数结果(pr#1363@Gitee)
|
||||
* 【core 】 增加`MapValueProvider`和`RecordConverter`并支持Record转换(issue#3985@Github)
|
||||
* 【core 】 `CalendarUtil`增加`isSameYear`和`calendar`方法(issue#3995@Github)
|
||||
* 【core 】 `DateUtil`增加`yyyy-MM-dd'T'HH:mmXXX`格式支持(pr#1367@Gitee)
|
||||
* 【core 】 `MapUtil`增加flatten方法(pr#1368@Gitee)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【extra 】 `Sftp``reconnectIfTimeout`方法改为捕获所有异常(issue#3989@Github)
|
||||
|
@ -285,6 +285,15 @@ public class DatePattern {
|
||||
*/
|
||||
public static final FastDateFormat UTC_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_WITH_XXX_OFFSET_PATTERN);
|
||||
|
||||
/**
|
||||
* UTC时间:yyyy-MM-dd'T'HH:mmXXX
|
||||
*/
|
||||
public static final String UTC_SIMPLE_MINUTE_WITH_XXX_OFFSET_PATTERN = "yyyy-MM-dd'T'HH:mmXXX";
|
||||
/**
|
||||
* UTC时间{@link FastDateFormat}:yyyy-MM-dd'T'HH:mmXXX
|
||||
*/
|
||||
public static final FastDateFormat UTC_SIMPLE_MINUTE_WITH_XXX_OFFSET_FORMAT = FastDateFormat.getInstance(UTC_SIMPLE_MINUTE_WITH_XXX_OFFSET_PATTERN);
|
||||
|
||||
/**
|
||||
* UTC时间:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
|
||||
*/
|
||||
|
@ -901,6 +901,9 @@ public class DateUtil extends CalendarUtil {
|
||||
// 带毫秒,格式类似:2018-09-13T05:34:31.999+08:00
|
||||
iso8601String = normalizeMillSeconds(iso8601String, ".", "+");
|
||||
return parse(iso8601String, DatePattern.UTC_MS_WITH_XXX_OFFSET_FORMAT);
|
||||
} else if (iso8601String.length() == 22 && StrUtil.count(iso8601String, ':') == 2) {
|
||||
// 精确到分钟,格式类似:2025-07-28T20:00+08:00
|
||||
return parse(iso8601String, DatePattern.UTC_SIMPLE_MINUTE_WITH_XXX_OFFSET_FORMAT);
|
||||
} else {
|
||||
// 格式类似:2018-09-13T05:34:31+08:00
|
||||
return parse(iso8601String, DatePattern.UTC_WITH_XXX_OFFSET_FORMAT);
|
||||
|
@ -1544,4 +1544,47 @@ public class MapUtil {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将多层级Map处理为一个层级Map类型
|
||||
*
|
||||
* @param map 入参Map
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @return 单层级Map返回值
|
||||
* @since 5.8.40
|
||||
*/
|
||||
public static <K, V> Map<K, V> flatten(final Map<K, V> map) {
|
||||
return flatten(map, new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归调用将多层级Map处理为一个层级Map类型
|
||||
*
|
||||
* @param map 入参Map
|
||||
* @param flatMap 单层级Map返回值
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @return 单层级Map返回值
|
||||
* @since 5.8.40
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K, V> Map<K, V> flatten(final Map<K, V> map, Map<K, V> flatMap) {
|
||||
Assert.notNull(map);
|
||||
if (null == flatMap) {
|
||||
flatMap = new HashMap<>();
|
||||
}
|
||||
|
||||
Map<K, V> finalFlatMap = flatMap;
|
||||
map.forEach((k, v) -> {
|
||||
// 避免嵌套循环
|
||||
if (v instanceof Map && v != map) {
|
||||
flatten((Map<K, V>) v, finalFlatMap);
|
||||
} else {
|
||||
finalFlatMap.put(k, v);
|
||||
}
|
||||
});
|
||||
|
||||
return flatMap;
|
||||
}
|
||||
}
|
||||
|
@ -667,6 +667,12 @@ public class DateUtilTest {
|
||||
dateStr = dt.toString(simpleDateFormat);
|
||||
assertEquals("2018-09-13 13:34:39.999", dateStr);
|
||||
|
||||
dateStr1 = "2025-07-28T20:00+08:00";
|
||||
dt = DateUtil.parse(dateStr1);
|
||||
assert dt != null;
|
||||
dateStr = dt.toString();
|
||||
assertEquals("2025-07-28 20:00:00", dateStr);
|
||||
|
||||
// 使用UTC时区
|
||||
dateStr1 = "2018-09-13T13:34:39.99";
|
||||
dt = DateUtil.parse(dateStr1);
|
||||
|
@ -862,4 +862,29 @@ public class MapUtilTest {
|
||||
assertEquals(0, MapUtil.get(map, "age", new TypeReference<Integer>() {
|
||||
}, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void flattenMapReturnsTest() {
|
||||
Map<String, String> clothes = new HashMap<>();
|
||||
clothes.put("clothesName", "ANTA");
|
||||
clothes.put("clothesPrice", "200");
|
||||
|
||||
Map<String, Object> person = new HashMap<>();
|
||||
person.put("personName", "XXXX");
|
||||
person.put("clothes", clothes);
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("home", "AAA");
|
||||
map.put("person", person);
|
||||
|
||||
Map<String, Object> flattenMap = MapUtil.flatten(map);
|
||||
assertEquals("ANTA", MapUtil.get(flattenMap, "clothesName", new TypeReference<String>() {
|
||||
}));
|
||||
assertEquals("200", MapUtil.get(flattenMap, "clothesPrice", new TypeReference<String>() {
|
||||
}));
|
||||
assertEquals("XXXX", MapUtil.get(flattenMap, "personName", new TypeReference<String>() {
|
||||
}));
|
||||
assertEquals("AAA", MapUtil.get(flattenMap, "home", new TypeReference<String>() {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user