mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
add /GlobalCustomFormat
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
# 5.7.3 (2021-06-25)
|
# 5.7.3 (2021-06-26)
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【core 】 增加Convert.toSet方法(issue#I3XFG2@Gitee)
|
* 【core 】 增加Convert.toSet方法(issue#I3XFG2@Gitee)
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
* 【core 】 新增JAXBUtil(pr#346@Gitee)
|
* 【core 】 新增JAXBUtil(pr#346@Gitee)
|
||||||
* 【poi 】 ExcelWriter新增setColumnStyleIfHasData和setRowStyleIfHasData(pr#347@Gitee)
|
* 【poi 】 ExcelWriter新增setColumnStyleIfHasData和setRowStyleIfHasData(pr#347@Gitee)
|
||||||
* 【json 】 用户自定义日期时间格式时,解析也读取此格式
|
* 【json 】 用户自定义日期时间格式时,解析也读取此格式
|
||||||
|
* 【core 】 增加可自定义日期格式GlobalCustomFormat
|
||||||
|
* 【jwt 】 JWT修改默认有序,并规定payload日期格式为秒数
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【json 】 修复XML转义字符的问题(issue#I3XH09@Gitee)
|
* 【json 】 修复XML转义字符的问题(issue#I3XH09@Gitee)
|
||||||
|
@@ -3,6 +3,7 @@ package cn.hutool.core.date;
|
|||||||
import cn.hutool.core.comparator.CompareUtil;
|
import cn.hutool.core.comparator.CompareUtil;
|
||||||
import cn.hutool.core.convert.NumberChineseFormatter;
|
import cn.hutool.core.convert.NumberChineseFormatter;
|
||||||
import cn.hutool.core.date.format.FastDateParser;
|
import cn.hutool.core.date.format.FastDateParser;
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
@@ -654,6 +655,15 @@ public class CalendarUtil {
|
|||||||
calendar.setLenient(lenient);
|
calendar.setLenient(lenient);
|
||||||
|
|
||||||
for (final String parsePattern : parsePatterns) {
|
for (final String parsePattern : parsePatterns) {
|
||||||
|
if(GlobalCustomFormat.isCustomFormat(parsePattern)){
|
||||||
|
final Date parse = GlobalCustomFormat.parse(str, parsePattern);
|
||||||
|
if(null == parse){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
calendar.setTime(parse);
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl);
|
final FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl);
|
||||||
calendar.clear();
|
calendar.clear();
|
||||||
try {
|
try {
|
||||||
|
@@ -3,6 +3,7 @@ package cn.hutool.core.date;
|
|||||||
import cn.hutool.core.date.format.DateParser;
|
import cn.hutool.core.date.format.DateParser;
|
||||||
import cn.hutool.core.date.format.DatePrinter;
|
import cn.hutool.core.date.format.DatePrinter;
|
||||||
import cn.hutool.core.date.format.FastDateFormat;
|
import cn.hutool.core.date.format.FastDateFormat;
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@@ -251,7 +252,9 @@ public class DateTime extends Date {
|
|||||||
* @see DatePattern
|
* @see DatePattern
|
||||||
*/
|
*/
|
||||||
public DateTime(CharSequence dateStr, String format) {
|
public DateTime(CharSequence dateStr, String format) {
|
||||||
this(dateStr, DateUtil.newSimpleFormat(format));
|
this(GlobalCustomFormat.isCustomFormat(format)
|
||||||
|
? GlobalCustomFormat.parse(dateStr, format)
|
||||||
|
: parse(dateStr, DateUtil.newSimpleFormat(format)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -5,6 +5,7 @@ import cn.hutool.core.comparator.CompareUtil;
|
|||||||
import cn.hutool.core.date.format.DateParser;
|
import cn.hutool.core.date.format.DateParser;
|
||||||
import cn.hutool.core.date.format.DatePrinter;
|
import cn.hutool.core.date.format.DatePrinter;
|
||||||
import cn.hutool.core.date.format.FastDateFormat;
|
import cn.hutool.core.date.format.FastDateFormat;
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.PatternPool;
|
import cn.hutool.core.lang.PatternPool;
|
||||||
import cn.hutool.core.util.CharUtil;
|
import cn.hutool.core.util.CharUtil;
|
||||||
@@ -488,6 +489,11 @@ public class DateUtil extends CalendarUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查自定义格式
|
||||||
|
if(GlobalCustomFormat.isCustomFormat(format)){
|
||||||
|
return GlobalCustomFormat.format(date, format);
|
||||||
|
}
|
||||||
|
|
||||||
TimeZone timeZone = null;
|
TimeZone timeZone = null;
|
||||||
if (date instanceof DateTime) {
|
if (date instanceof DateTime) {
|
||||||
timeZone = ((DateTime) date).getTimeZone();
|
timeZone = ((DateTime) date).getTimeZone();
|
||||||
@@ -696,6 +702,10 @@ public class DateUtil extends CalendarUtil {
|
|||||||
* @since 4.5.18
|
* @since 4.5.18
|
||||||
*/
|
*/
|
||||||
public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
|
public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
|
||||||
|
if(GlobalCustomFormat.isCustomFormat(format)){
|
||||||
|
// 自定义格式化器忽略Locale
|
||||||
|
return new DateTime(GlobalCustomFormat.parse(dateStr, format));
|
||||||
|
}
|
||||||
return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null));
|
return new DateTime(dateStr, DateUtil.newSimpleFormat(format, locale, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.core.date;
|
package cn.hutool.core.date;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.ReUtil;
|
import cn.hutool.core.util.ReUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
@@ -139,7 +140,7 @@ public class LocalDateTimeUtil {
|
|||||||
* 毫秒转{@link LocalDateTime},结果会产生时间偏移
|
* 毫秒转{@link LocalDateTime},结果会产生时间偏移
|
||||||
*
|
*
|
||||||
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
|
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
|
||||||
* @param timeZone 时区
|
* @param timeZone 时区
|
||||||
* @return {@link LocalDateTime}
|
* @return {@link LocalDateTime}
|
||||||
*/
|
*/
|
||||||
public static LocalDateTime of(long epochMilli, TimeZone timeZone) {
|
public static LocalDateTime of(long epochMilli, TimeZone timeZone) {
|
||||||
@@ -174,8 +175,8 @@ public class LocalDateTimeUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(temporalAccessor instanceof LocalDate){
|
if (temporalAccessor instanceof LocalDate) {
|
||||||
return ((LocalDate)temporalAccessor).atStartOfDay();
|
return ((LocalDate) temporalAccessor).atStartOfDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
return LocalDateTime.of(
|
return LocalDateTime.of(
|
||||||
@@ -201,8 +202,8 @@ public class LocalDateTimeUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(temporalAccessor instanceof LocalDateTime){
|
if (temporalAccessor instanceof LocalDateTime) {
|
||||||
return ((LocalDateTime)temporalAccessor).toLocalDate();
|
return ((LocalDateTime) temporalAccessor).toLocalDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return LocalDate.of(
|
return LocalDate.of(
|
||||||
@@ -215,11 +216,11 @@ public class LocalDateTimeUtil {
|
|||||||
/**
|
/**
|
||||||
* 解析日期时间字符串为{@link LocalDateTime},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30
|
* 解析日期时间字符串为{@link LocalDateTime},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30
|
||||||
*
|
*
|
||||||
* @param text 日期时间字符串
|
* @param text 日期时间字符串
|
||||||
* @return {@link LocalDateTime}
|
* @return {@link LocalDateTime}
|
||||||
*/
|
*/
|
||||||
public static LocalDateTime parse(CharSequence text) {
|
public static LocalDateTime parse(CharSequence text) {
|
||||||
return parse(text, (DateTimeFormatter)null);
|
return parse(text, (DateTimeFormatter) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,23 +253,27 @@ public class LocalDateTimeUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GlobalCustomFormat.isCustomFormat(format)){
|
||||||
|
return of(GlobalCustomFormat.parse(text, format));
|
||||||
|
}
|
||||||
|
|
||||||
DateTimeFormatter formatter = null;
|
DateTimeFormatter formatter = null;
|
||||||
if(StrUtil.isNotBlank(format)){
|
if (StrUtil.isNotBlank(format)) {
|
||||||
// 修复yyyyMMddHHmmssSSS格式不能解析的问题
|
// 修复yyyyMMddHHmmssSSS格式不能解析的问题
|
||||||
// fix issue#1082
|
// fix issue#1082
|
||||||
//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second
|
//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second
|
||||||
// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085
|
// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085
|
||||||
if(StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)){
|
if (StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)) {
|
||||||
final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);
|
final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);
|
||||||
if(ReUtil.isMatch("[S]{1,2}", fraction)){
|
if (ReUtil.isMatch("[S]{1,2}", fraction)) {
|
||||||
//将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式,用0补
|
//将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式,用0补
|
||||||
text += StrUtil.repeat('0', 3-fraction.length());
|
text += StrUtil.repeat('0', 3 - fraction.length());
|
||||||
}
|
}
|
||||||
formatter = new DateTimeFormatterBuilder()
|
formatter = new DateTimeFormatterBuilder()
|
||||||
.appendPattern(DatePattern.PURE_DATETIME_PATTERN)
|
.appendPattern(DatePattern.PURE_DATETIME_PATTERN)
|
||||||
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
|
||||||
.toFormatter();
|
.toFormatter();
|
||||||
} else{
|
} else {
|
||||||
formatter = DateTimeFormatter.ofPattern(format);
|
formatter = DateTimeFormatter.ofPattern(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,12 +284,12 @@ public class LocalDateTimeUtil {
|
|||||||
/**
|
/**
|
||||||
* 解析日期时间字符串为{@link LocalDate},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30
|
* 解析日期时间字符串为{@link LocalDate},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30
|
||||||
*
|
*
|
||||||
* @param text 日期时间字符串
|
* @param text 日期时间字符串
|
||||||
* @return {@link LocalDate}
|
* @return {@link LocalDate}
|
||||||
* @since 5.3.10
|
* @since 5.3.10
|
||||||
*/
|
*/
|
||||||
public static LocalDate parseDate(CharSequence text) {
|
public static LocalDate parseDate(CharSequence text) {
|
||||||
return parseDate(text, (DateTimeFormatter)null);
|
return parseDate(text, (DateTimeFormatter) null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -323,7 +328,7 @@ public class LocalDateTimeUtil {
|
|||||||
/**
|
/**
|
||||||
* 格式化日期时间为yyyy-MM-dd HH:mm:ss格式
|
* 格式化日期时间为yyyy-MM-dd HH:mm:ss格式
|
||||||
*
|
*
|
||||||
* @param time {@link LocalDateTime}
|
* @param time {@link LocalDateTime}
|
||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
* @since 5.3.11
|
* @since 5.3.11
|
||||||
*/
|
*/
|
||||||
@@ -350,16 +355,13 @@ public class LocalDateTimeUtil {
|
|||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
*/
|
*/
|
||||||
public static String format(LocalDateTime time, String format) {
|
public static String format(LocalDateTime time, String format) {
|
||||||
if (null == time) {
|
return TemporalAccessorUtil.format(time, format);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return format(time, DateTimeFormatter.ofPattern(format));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化日期时间为yyyy-MM-dd格式
|
* 格式化日期时间为yyyy-MM-dd格式
|
||||||
*
|
*
|
||||||
* @param date {@link LocalDate}
|
* @param date {@link LocalDate}
|
||||||
* @return 格式化后的字符串
|
* @return 格式化后的字符串
|
||||||
* @since 5.3.11
|
* @since 5.3.11
|
||||||
*/
|
*/
|
||||||
@@ -478,8 +480,8 @@ public class LocalDateTimeUtil {
|
|||||||
*
|
*
|
||||||
* @param temporalAccessor Date对象
|
* @param temporalAccessor Date对象
|
||||||
* @return {@link Instant}对象
|
* @return {@link Instant}对象
|
||||||
* @since 5.4.1
|
|
||||||
* @see TemporalAccessorUtil#toEpochMilli(TemporalAccessor)
|
* @see TemporalAccessorUtil#toEpochMilli(TemporalAccessor)
|
||||||
|
* @since 5.4.1
|
||||||
*/
|
*/
|
||||||
public static long toEpochMilli(TemporalAccessor temporalAccessor) {
|
public static long toEpochMilli(TemporalAccessor temporalAccessor) {
|
||||||
return TemporalAccessorUtil.toEpochMilli(temporalAccessor);
|
return TemporalAccessorUtil.toEpochMilli(temporalAccessor);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.core.date;
|
package cn.hutool.core.date;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -83,6 +84,11 @@ public class TemporalAccessorUtil extends TemporalUtil{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查自定义格式
|
||||||
|
if(GlobalCustomFormat.isCustomFormat(format)){
|
||||||
|
return GlobalCustomFormat.format(time, format);
|
||||||
|
}
|
||||||
|
|
||||||
final DateTimeFormatter formatter = StrUtil.isBlank(format)
|
final DateTimeFormatter formatter = StrUtil.isBlank(format)
|
||||||
? null : DateTimeFormatter.ofPattern(format);
|
? null : DateTimeFormatter.ofPattern(format);
|
||||||
|
|
||||||
|
119
hutool-core/src/main/java/cn/hutool/core/date/format/GlobalCustomFormat.java
Executable file
119
hutool-core/src/main/java/cn/hutool/core/date/format/GlobalCustomFormat.java
Executable file
@@ -0,0 +1,119 @@
|
|||||||
|
package cn.hutool.core.date.format;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
|
||||||
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局自定义格式<br>
|
||||||
|
* 用于定义用户指定的日期格式和输出日期的关系
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
* @since 5.7.2
|
||||||
|
*/
|
||||||
|
public class GlobalCustomFormat {
|
||||||
|
|
||||||
|
public static final String FORMAT_SECONDS = "#sss";
|
||||||
|
public static final String FORMAT_MILLISECONDS = "#SSS";
|
||||||
|
|
||||||
|
private static final Map<CharSequence, Function<Date, String>> formatterMap;
|
||||||
|
private static final Map<CharSequence, Function<CharSequence, Date>> parserMap;
|
||||||
|
|
||||||
|
static {
|
||||||
|
formatterMap = new ConcurrentHashMap<>();
|
||||||
|
parserMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// Hutool预设的几种自定义格式
|
||||||
|
putFormatter(FORMAT_SECONDS, (date) -> String.valueOf(Math.floorDiv(date.getTime(), 1000)));
|
||||||
|
putParser(FORMAT_SECONDS, (dateStr) -> DateUtil.date(Math.multiplyExact(Long.parseLong(dateStr.toString()), 1000)));
|
||||||
|
|
||||||
|
putFormatter(FORMAT_MILLISECONDS, (date) -> String.valueOf(date.getTime()));
|
||||||
|
putParser(FORMAT_MILLISECONDS, (dateStr) -> DateUtil.date(Long.parseLong(dateStr.toString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入日期格式化规则
|
||||||
|
*
|
||||||
|
* @param format 格式
|
||||||
|
* @param func 格式化函数
|
||||||
|
*/
|
||||||
|
public static void putFormatter(String format, Function<Date, String> func) {
|
||||||
|
Assert.notNull(format, "Format must be not null !");
|
||||||
|
Assert.notNull(func, "Function must be not null !");
|
||||||
|
formatterMap.put(format, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加入日期解析规则
|
||||||
|
*
|
||||||
|
* @param format 格式
|
||||||
|
* @param func 解析函数
|
||||||
|
*/
|
||||||
|
public static void putParser(String format, Function<CharSequence, Date> func) {
|
||||||
|
Assert.notNull(format, "Format must be not null !");
|
||||||
|
Assert.notNull(func, "Function must be not null !");
|
||||||
|
parserMap.put(format, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查指定格式是否为自定义格式
|
||||||
|
*
|
||||||
|
* @param format 格式
|
||||||
|
* @return 是否为自定义格式
|
||||||
|
*/
|
||||||
|
public static boolean isCustomFormat(String format) {
|
||||||
|
return formatterMap.containsKey(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义格式格式化日期
|
||||||
|
*
|
||||||
|
* @param date 日期
|
||||||
|
* @param format 自定义格式
|
||||||
|
* @return 格式化后的日期
|
||||||
|
*/
|
||||||
|
public static String format(Date date, CharSequence format) {
|
||||||
|
if (null != formatterMap) {
|
||||||
|
final Function<Date, String> func = formatterMap.get(format);
|
||||||
|
if (null != func) {
|
||||||
|
return func.apply(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义格式格式化日期
|
||||||
|
*
|
||||||
|
* @param temporalAccessor 日期
|
||||||
|
* @param format 自定义格式
|
||||||
|
* @return 格式化后的日期
|
||||||
|
*/
|
||||||
|
public static String format(TemporalAccessor temporalAccessor, CharSequence format) {
|
||||||
|
return format(DateUtil.date(temporalAccessor), format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用自定义格式解析日期
|
||||||
|
*
|
||||||
|
* @param dateStr 日期字符串
|
||||||
|
* @param format 自定义格式
|
||||||
|
* @return 格式化后的日期
|
||||||
|
*/
|
||||||
|
public static Date parse(CharSequence dateStr, String format) {
|
||||||
|
if (null != parserMap) {
|
||||||
|
final Function<CharSequence, Date> func = parserMap.get(format);
|
||||||
|
if (null != func) {
|
||||||
|
return func.apply(dateStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -62,6 +62,7 @@ public class JAXBUtil {
|
|||||||
/**
|
/**
|
||||||
* xml转换成JavaBean
|
* xml转换成JavaBean
|
||||||
*
|
*
|
||||||
|
* @param <T> Bean类型
|
||||||
* @param xml XML字符串
|
* @param xml XML字符串
|
||||||
* @param c Bean类型
|
* @param c Bean类型
|
||||||
* @return bean
|
* @return bean
|
||||||
|
@@ -72,6 +72,30 @@ public class DateUtilTest {
|
|||||||
Assert.assertEquals("00:00:00", formatTime);
|
Assert.assertEquals("00:00:00", formatTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatAndParseCustomTest() {
|
||||||
|
String dateStr = "2017-03-01";
|
||||||
|
Date date = DateUtil.parse(dateStr);
|
||||||
|
|
||||||
|
String format = DateUtil.format(date, "#sss");
|
||||||
|
Assert.assertEquals("1488297600", format);
|
||||||
|
|
||||||
|
final DateTime parse = DateUtil.parse(format, "#sss");
|
||||||
|
Assert.assertEquals(date, parse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatAndParseCustomTest2() {
|
||||||
|
String dateStr = "2017-03-01";
|
||||||
|
Date date = DateUtil.parse(dateStr);
|
||||||
|
|
||||||
|
String format = DateUtil.format(date, "#SSS");
|
||||||
|
Assert.assertEquals("1488297600000", format);
|
||||||
|
|
||||||
|
final DateTime parse = DateUtil.parse(format, "#SSS");
|
||||||
|
Assert.assertEquals(date, parse);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void beginAndEndTest() {
|
public void beginAndEndTest() {
|
||||||
String dateStr = "2017-03-01 00:33:23";
|
String dateStr = "2017-03-01 00:33:23";
|
||||||
@@ -883,6 +907,6 @@ public class DateUtilTest {
|
|||||||
public void parseNotFitTest(){
|
public void parseNotFitTest(){
|
||||||
//https://github.com/looly/hutool/issues/1332
|
//https://github.com/looly/hutool/issues/1332
|
||||||
// 在日期格式不匹配的时候,测试是否正常报错
|
// 在日期格式不匹配的时候,测试是否正常报错
|
||||||
final DateTime parse = DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN);
|
DateUtil.parse("2020-12-23", DatePattern.PURE_DATE_PATTERN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,4 +20,15 @@ public class TemporalAccessorUtilTest {
|
|||||||
final String format = TemporalAccessorUtil.format(LocalTime.MIN, DatePattern.NORM_DATETIME_PATTERN);
|
final String format = TemporalAccessorUtil.format(LocalTime.MIN, DatePattern.NORM_DATETIME_PATTERN);
|
||||||
Assert.assertEquals(today + " 00:00:00", format);
|
Assert.assertEquals(today + " 00:00:00", format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void formatCustomTest(){
|
||||||
|
final String today = TemporalAccessorUtil.format(
|
||||||
|
LocalDate.of(2021, 6, 26), "#sss");
|
||||||
|
Assert.assertEquals("1624636800", today);
|
||||||
|
|
||||||
|
final String today2 = TemporalAccessorUtil.format(
|
||||||
|
LocalDate.of(2021, 6, 26), "#SSS");
|
||||||
|
Assert.assertEquals("1624636800000", today2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package cn.hutool.json;
|
|||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.date.TemporalAccessorUtil;
|
import cn.hutool.core.date.TemporalAccessorUtil;
|
||||||
|
import cn.hutool.core.date.format.GlobalCustomFormat;
|
||||||
import cn.hutool.core.util.CharUtil;
|
import cn.hutool.core.util.CharUtil;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
@@ -167,10 +168,6 @@ final class InternalJSONUtil {
|
|||||||
try {
|
try {
|
||||||
if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) {
|
if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) {
|
||||||
// pr#192@Gitee,Double会出现小数精度丢失问题,此处使用BigDecimal
|
// pr#192@Gitee,Double会出现小数精度丢失问题,此处使用BigDecimal
|
||||||
//double d = Double.parseDouble(string);
|
|
||||||
//if (false == Double.isInfinite(d) && false == Double.isNaN(d)) {
|
|
||||||
// return d;
|
|
||||||
//}
|
|
||||||
return new BigDecimal(string);
|
return new BigDecimal(string);
|
||||||
} else {
|
} else {
|
||||||
final long myLong = Long.parseLong(string);
|
final long myLong = Long.parseLong(string);
|
||||||
@@ -275,6 +272,12 @@ final class InternalJSONUtil {
|
|||||||
} else{
|
} else{
|
||||||
dateStr = DateUtil.format(Convert.toDate(dateObj), format);
|
dateStr = DateUtil.format(Convert.toDate(dateObj), format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(GlobalCustomFormat.FORMAT_SECONDS.equals(format)
|
||||||
|
|| GlobalCustomFormat.FORMAT_MILLISECONDS.equals(format)){
|
||||||
|
// Hutool自定义的秒和毫秒表示,默认不包装双引号
|
||||||
|
return dateStr;
|
||||||
|
}
|
||||||
//用户定义了日期格式
|
//用户定义了日期格式
|
||||||
return JSONUtil.quote(dateStr);
|
return JSONUtil.quote(dateStr);
|
||||||
}
|
}
|
||||||
|
@@ -113,21 +113,25 @@ public interface JSONGetter<K> extends OptNullBasicTypeFromObjectGetter<K> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Date getDate(K key, Date defaultValue){
|
default Date getDate(K key, Date defaultValue){
|
||||||
|
// 默认转换
|
||||||
|
final Object obj = getObj(key);
|
||||||
|
if (null == obj) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if(obj instanceof Date){
|
||||||
|
return (Date) obj;
|
||||||
|
}
|
||||||
|
|
||||||
String format = OptionalBean.ofNullable(getConfig()).getBean(JSONConfig::getDateFormat).get();
|
String format = OptionalBean.ofNullable(getConfig()).getBean(JSONConfig::getDateFormat).get();
|
||||||
if(StrUtil.isNotBlank(format)){
|
if(StrUtil.isNotBlank(format)){
|
||||||
// 用户指定了日期格式,获取日期属性时使用对应格式
|
// 用户指定了日期格式,获取日期属性时使用对应格式
|
||||||
final String str = getStr(key);
|
final String str = Convert.toStr(obj);
|
||||||
if(null == str){
|
if(null == str){
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
return DateUtil.parse(str, format);
|
return DateUtil.parse(str, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认转换
|
|
||||||
final Object obj = getObj(key);
|
|
||||||
if (null == obj) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return Convert.toDate(obj, defaultValue);
|
return Convert.toDate(obj, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -450,6 +450,27 @@ public class JSONObjectTest {
|
|||||||
Assert.assertEquals(DateUtil.beginOfDay(date), parse.getDate("date"));
|
Assert.assertEquals(DateUtil.beginOfDay(date), parse.getDate("date"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setCustomDateFormatTest(){
|
||||||
|
JSONConfig jsonConfig = JSONConfig.create();
|
||||||
|
jsonConfig.setDateFormat("#sss");
|
||||||
|
jsonConfig.setOrder(true);
|
||||||
|
|
||||||
|
Date date = DateUtil.parse("2020-06-05 11:16:11");
|
||||||
|
JSONObject json = new JSONObject(jsonConfig);
|
||||||
|
json.set("date", date);
|
||||||
|
json.set("bbb", "222");
|
||||||
|
json.set("aaa", "123");
|
||||||
|
|
||||||
|
String jsonStr = "{\"date\":1591326971,\"bbb\":\"222\",\"aaa\":\"123\"}";
|
||||||
|
|
||||||
|
Assert.assertEquals(jsonStr, json.toString());
|
||||||
|
|
||||||
|
// 解析测试
|
||||||
|
final JSONObject parse = JSONUtil.parseObj(jsonStr, jsonConfig);
|
||||||
|
Assert.assertEquals(date, parse.getDate("date"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getTimestampTest(){
|
public void getTimestampTest(){
|
||||||
String timeStr = "1970-01-01 00:00:00";
|
String timeStr = "1970-01-01 00:00:00";
|
||||||
|
@@ -3,6 +3,7 @@ package cn.hutool.jwt;
|
|||||||
import cn.hutool.core.codec.Base64;
|
import cn.hutool.core.codec.Base64;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.json.JSONConfig;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
@@ -19,11 +20,9 @@ import java.util.Map;
|
|||||||
public class Claims implements Serializable {
|
public class Claims implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private JSONObject claimJSON;
|
private final JSONConfig CONFIG = JSONConfig.create().setDateFormat("#sss").setOrder(true);
|
||||||
|
|
||||||
public Claims() {
|
private JSONObject claimJSON;
|
||||||
this.claimJSON = new JSONObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加Claims属性,如果属性值为{@code null},则移除这个属性
|
* 增加Claims属性,如果属性值为{@code null},则移除这个属性
|
||||||
@@ -32,6 +31,7 @@ public class Claims implements Serializable {
|
|||||||
* @param value 属性值
|
* @param value 属性值
|
||||||
*/
|
*/
|
||||||
protected void setClaim(String name, Object value) {
|
protected void setClaim(String name, Object value) {
|
||||||
|
init();
|
||||||
Assert.notNull(name, "Name must be not null!");
|
Assert.notNull(name, "Name must be not null!");
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
claimJSON.remove(name);
|
claimJSON.remove(name);
|
||||||
@@ -59,6 +59,7 @@ public class Claims implements Serializable {
|
|||||||
* @return 属性
|
* @return 属性
|
||||||
*/
|
*/
|
||||||
public Object getClaim(String name) {
|
public Object getClaim(String name) {
|
||||||
|
init();
|
||||||
return this.claimJSON.getObj(name);
|
return this.claimJSON.getObj(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ public class Claims implements Serializable {
|
|||||||
* @return JSON字符串
|
* @return JSON字符串
|
||||||
*/
|
*/
|
||||||
public JSONObject getClaimsJson() {
|
public JSONObject getClaimsJson() {
|
||||||
|
init();
|
||||||
return this.claimJSON;
|
return this.claimJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +80,18 @@ public class Claims implements Serializable {
|
|||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
*/
|
*/
|
||||||
public void parse(String tokenPart, Charset charset) {
|
public void parse(String tokenPart, Charset charset) {
|
||||||
this.claimJSON = JSONUtil.parseObj(Base64.decodeStr(tokenPart, charset));
|
this.claimJSON = JSONUtil.parseObj(Base64.decodeStr(tokenPart, charset), CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
init();
|
||||||
return this.claimJSON.toString();
|
return this.claimJSON.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void init(){
|
||||||
|
if(null == this.claimJSON){
|
||||||
|
this.claimJSON = new JSONObject(CONFIG);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.jwt;
|
package cn.hutool.jwt;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.crypto.KeyUtil;
|
import cn.hutool.crypto.KeyUtil;
|
||||||
import cn.hutool.jwt.signers.AlgorithmUtil;
|
import cn.hutool.jwt.signers.AlgorithmUtil;
|
||||||
import cn.hutool.jwt.signers.JWTSigner;
|
import cn.hutool.jwt.signers.JWTSigner;
|
||||||
@@ -113,6 +114,7 @@ public class JWTSignerTest {
|
|||||||
.setPayload("sub", "1234567890")
|
.setPayload("sub", "1234567890")
|
||||||
.setPayload("name", "looly")
|
.setPayload("name", "looly")
|
||||||
.setPayload("admin", true)
|
.setPayload("admin", true)
|
||||||
|
.setExpiresAt(DateUtil.tomorrow())
|
||||||
.setSigner(signer);
|
.setSigner(signer);
|
||||||
|
|
||||||
String token = jwt.sign();
|
String token = jwt.sign();
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.jwt;
|
package cn.hutool.jwt;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@@ -14,11 +15,12 @@ public class JWTTest {
|
|||||||
.setPayload("sub", "1234567890")
|
.setPayload("sub", "1234567890")
|
||||||
.setPayload("name", "looly")
|
.setPayload("name", "looly")
|
||||||
.setPayload("admin", true)
|
.setPayload("admin", true)
|
||||||
|
.setPayload(RegisteredPayload.EXPIRES_AT, DateUtil.parse("2022-01-01"))
|
||||||
.setKey(key);
|
.setKey(key);
|
||||||
|
|
||||||
String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
|
String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
|
||||||
"eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9." +
|
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Imxvb2x5IiwiYWRtaW4iOnRydWUsImV4cCI6IjE2NDA5NjY0MDAifQ." +
|
||||||
"U2aQkC2THYV9L0fTN-yBBI7gmo5xhmvMhATtu8v0zEA";
|
"c9qo9Z9vdN2gulvOEReU9iEi0bqgyVqjaNKbP1DmTL4";
|
||||||
|
|
||||||
String token = jwt.sign();
|
String token = jwt.sign();
|
||||||
Assert.assertEquals(token, rightToken);
|
Assert.assertEquals(token, rightToken);
|
||||||
|
Reference in New Issue
Block a user