mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add RegexDateParser
This commit is contained in:
parent
9a34a155c6
commit
47872b8380
@ -717,7 +717,7 @@ public class CalendarUtil {
|
||||
* @throws DateException if none of the date patterns were suitable
|
||||
* @since 5.3.11
|
||||
*/
|
||||
public static Calendar parseByPatterns(final String str, final String... parsePatterns) throws DateException {
|
||||
public static Calendar parseByPatterns(final CharSequence str, final String... parsePatterns) throws DateException {
|
||||
return parseByPatterns(str, null, parsePatterns);
|
||||
}
|
||||
|
||||
@ -734,7 +734,7 @@ public class CalendarUtil {
|
||||
* @throws DateException if none of the date patterns were suitable
|
||||
* @since 5.3.11
|
||||
*/
|
||||
public static Calendar parseByPatterns(final String str, final Locale locale, final String... parsePatterns) throws DateException {
|
||||
public static Calendar parseByPatterns(final CharSequence str, final Locale locale, final String... parsePatterns) throws DateException {
|
||||
return parseByPatterns(str, locale, true, parsePatterns);
|
||||
}
|
||||
|
||||
@ -753,7 +753,7 @@ public class CalendarUtil {
|
||||
* @see java.util.Calendar#isLenient()
|
||||
* @since 5.3.11
|
||||
*/
|
||||
public static Calendar parseByPatterns(final String str, final Locale locale, final boolean lenient, final String... parsePatterns) throws DateException {
|
||||
public static Calendar parseByPatterns(final CharSequence str, final Locale locale, final boolean lenient, final String... parsePatterns) throws DateException {
|
||||
if (str == null || parsePatterns == null) {
|
||||
throw new IllegalArgumentException("Date and Patterns must not be null");
|
||||
}
|
||||
|
@ -37,9 +37,9 @@ public final class DateBuilder {
|
||||
// region ----- fields
|
||||
// 年份
|
||||
private int year;
|
||||
// 月份
|
||||
// 月份,从1开始
|
||||
private int month;
|
||||
// 周数
|
||||
// 周数,ISO8601规范,1代表Monday,2代表Tuesday,以此类推。
|
||||
private int week;
|
||||
// 日
|
||||
private int day;
|
||||
@ -88,18 +88,18 @@ public final class DateBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月份。
|
||||
* 获取月份,从1开始。
|
||||
*
|
||||
* @return 返回设置的月份。
|
||||
* @return 返回设置的月份,从1开始。
|
||||
*/
|
||||
public int getMonth() {
|
||||
return month;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置月份。
|
||||
* 设置月份,从1开始。
|
||||
*
|
||||
* @param month 要设置的月份。
|
||||
* @param month 要设置的月份,从1开始。
|
||||
* @return this
|
||||
*/
|
||||
public DateBuilder setMonth(final int month) {
|
||||
@ -117,9 +117,9 @@ public final class DateBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日期构建器的周数。
|
||||
* 设置日期构建器的周数,ISO8601规范,1代表Monday,2代表Tuesday,以此类推。
|
||||
*
|
||||
* @param week 指定的周数,通常用于构建具体的日期对象。
|
||||
* @param week 指定的周数,通常用于构建具体的日期对象,ISO8601规范,1代表Monday,2代表Tuesday,以此类推。
|
||||
* @return this。
|
||||
*/
|
||||
public DateBuilder setWeek(final int week) {
|
||||
|
@ -344,17 +344,17 @@ public class FastDateFormat extends Format implements PositionDateParser, DatePr
|
||||
|
||||
// ----------------------------------------------------------------------- Parsing
|
||||
@Override
|
||||
public Date parse(final String source) throws DateException {
|
||||
public Date parse(final CharSequence source) throws DateException {
|
||||
return parser.parse(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(final String source, final ParsePosition pos) {
|
||||
public Date parse(final CharSequence source, final ParsePosition pos) {
|
||||
return parser.parse(source, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
|
||||
public boolean parse(final CharSequence source, final ParsePosition pos, final Calendar calendar) {
|
||||
return parser.parse(source, pos, calendar);
|
||||
}
|
||||
|
||||
|
@ -31,5 +31,5 @@ public interface DateParser extends DateBasic{
|
||||
* @return {@link Date}对象
|
||||
* @throws DateException 转换异常,被转换的字符串格式错误。
|
||||
*/
|
||||
Date parse(String source) throws DateException;
|
||||
Date parse(CharSequence source) throws DateException;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.date.format.FastDateFormat;
|
||||
import org.dromara.hutool.core.date.format.FastDatePrinter;
|
||||
import org.dromara.hutool.core.date.format.SimpleDateBasic;
|
||||
import org.dromara.hutool.core.map.concurrent.SafeConcurrentHashMap;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
@ -224,7 +225,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(final String source) throws DateException {
|
||||
public Date parse(final CharSequence source) throws DateException {
|
||||
final ParsePosition pp = new ParsePosition(0);
|
||||
final Date date = parse(source, pp);
|
||||
if (date == null) {
|
||||
@ -239,7 +240,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(final String source, final ParsePosition pos) {
|
||||
public Date parse(final CharSequence source, final ParsePosition pos) {
|
||||
// timing tests indicate getting new instance is 19% faster than cloning
|
||||
final Calendar cal = Calendar.getInstance(timeZone, locale);
|
||||
cal.clear();
|
||||
@ -248,7 +249,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
|
||||
public boolean parse(final CharSequence source, final ParsePosition pos, final Calendar calendar) {
|
||||
final ListIterator<StrategyAndWidth> lt = patterns.listIterator();
|
||||
while (lt.hasNext()) {
|
||||
final StrategyAndWidth strategyAndWidth = lt.next();
|
||||
@ -337,7 +338,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract boolean parse(FastDateParser parser, Calendar calendar, String source, ParsePosition pos, int maxWidth);
|
||||
abstract boolean parse(FastDateParser parser, Calendar calendar, CharSequence source, ParsePosition pos, int maxWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,8 +357,8 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) {
|
||||
final Matcher matcher = pattern.matcher(source.substring(pos.getIndex()));
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final CharSequence source, final ParsePosition pos, final int maxWidth) {
|
||||
final Matcher matcher = pattern.matcher(source.subSequence(pos.getIndex(), source.length()));
|
||||
if (!matcher.lookingAt()) {
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
return false;
|
||||
@ -486,7 +487,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) {
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final CharSequence source, final ParsePosition pos, final int maxWidth) {
|
||||
for (int idx = 0; idx < formatField.length(); ++idx) {
|
||||
final int sIdx = idx + pos.getIndex();
|
||||
if (sIdx == source.length()) {
|
||||
@ -558,7 +559,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) {
|
||||
boolean parse(final FastDateParser parser, final Calendar calendar, final CharSequence source, final ParsePosition pos, final int maxWidth) {
|
||||
int idx = pos.getIndex();
|
||||
int last = source.length();
|
||||
|
||||
@ -590,7 +591,7 @@ public class FastDateParser extends SimpleDateBasic implements PositionDateParse
|
||||
return false;
|
||||
}
|
||||
|
||||
final int value = Integer.parseInt(source.substring(pos.getIndex(), idx));
|
||||
final int value = Integer.parseInt(StrUtil.sub(source, pos.getIndex(), idx));
|
||||
pos.setIndex(idx);
|
||||
|
||||
calendar.set(field, modify(parser, value));
|
||||
|
@ -48,7 +48,7 @@ public class ISO8601DateParser extends DefaultDateBasic implements PredicateDate
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(String source) throws DateException{
|
||||
public DateTime parse(CharSequence source) throws DateException{
|
||||
final int length = source.length();
|
||||
if (StrUtil.contains(source, 'Z')) {
|
||||
if (length == DatePattern.UTC_PATTERN.length() - 4) {
|
||||
@ -65,7 +65,7 @@ public class ISO8601DateParser extends DefaultDateBasic implements PredicateDate
|
||||
}
|
||||
} else if (StrUtil.contains(source, '+')) {
|
||||
// 去除类似2019-06-01T19:45:43 +08:00加号前的空格
|
||||
source = source.replace(" +", "+");
|
||||
source = StrUtil.replace(source, " +", "+");
|
||||
final String zoneOffset = StrUtil.subAfter(source, '+', true);
|
||||
if (StrUtil.isBlank(zoneOffset)) {
|
||||
throw new DateException("Invalid format: [{}]", source);
|
||||
@ -88,9 +88,9 @@ public class ISO8601DateParser extends DefaultDateBasic implements PredicateDate
|
||||
// Issue#2612,类似 2022-09-14T23:59:00-08:00 或者 2022-09-14T23:59:00-0800
|
||||
|
||||
// 去除类似2019-06-01T19:45:43 -08:00加号前的空格
|
||||
source = source.replace(" -", "-");
|
||||
source = StrUtil.replace(source, " -", "-");
|
||||
if(':' != source.charAt(source.length() - 3)){
|
||||
source = source.substring(0, source.length() - 2) + ":00";
|
||||
source = StrUtil.sub(source, 0, source.length() - 2) + ":00";
|
||||
}
|
||||
|
||||
if (StrUtil.contains(source, CharUtil.DOT)) {
|
||||
@ -128,7 +128,7 @@ public class ISO8601DateParser extends DefaultDateBasic implements PredicateDate
|
||||
* @return 规范之后的毫秒部分
|
||||
*/
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static String normalizeMillSeconds(final String dateStr, final CharSequence before, final CharSequence after) {
|
||||
private static String normalizeMillSeconds(final CharSequence dateStr, final CharSequence before, final CharSequence after) {
|
||||
if (StrUtil.isBlank(after)) {
|
||||
final String millOrNaco = StrUtil.subPre(StrUtil.subAfter(dateStr, before, true), 3);
|
||||
return StrUtil.subBefore(dateStr, before, true) + before + millOrNaco;
|
||||
|
@ -51,7 +51,7 @@ public class NormalDateParser extends DefaultDateBasic implements PredicateDateP
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(String source) throws DateException{
|
||||
public DateTime parse(CharSequence source) throws DateException{
|
||||
final int colonCount = StrUtil.count(source, CharUtil.COLON);
|
||||
switch (colonCount) {
|
||||
case 0:
|
||||
|
@ -80,7 +80,7 @@ public class PatternsDateParser extends DefaultDateBasic implements DateParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(final String source) {
|
||||
public DateTime parse(final CharSequence source) {
|
||||
return new DateTime(CalendarUtil.parseByPatterns(source, this.locale, this.parsePatterns));
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public interface PositionDateParser extends DateParser {
|
||||
* @param pos {@link ParsePosition}
|
||||
* @return {@link Date}
|
||||
*/
|
||||
Date parse(String source, ParsePosition pos);
|
||||
Date parse(CharSequence source, ParsePosition pos);
|
||||
|
||||
/**
|
||||
* 根据给定格式更新{@link Calendar}
|
||||
@ -46,5 +46,5 @@ public interface PositionDateParser extends DateParser {
|
||||
* @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated)
|
||||
* @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is out of range.
|
||||
*/
|
||||
boolean parse(String source, ParsePosition pos, Calendar calendar);
|
||||
boolean parse(CharSequence source, ParsePosition pos, Calendar calendar);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.dromara.hutool.core.date.DatePattern;
|
||||
import org.dromara.hutool.core.date.DateTime;
|
||||
import org.dromara.hutool.core.date.format.DefaultDateBasic;
|
||||
import org.dromara.hutool.core.math.NumberUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
/**
|
||||
* 纯数字的日期字符串解析,支持格式包括;
|
||||
@ -45,7 +46,7 @@ public class PureDateParser extends DefaultDateBasic implements PredicateDatePar
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(final String source) throws DateException {
|
||||
public DateTime parse(final CharSequence source) throws DateException {
|
||||
final int length = source.length();
|
||||
// 纯数字形式
|
||||
if (length == DatePattern.PURE_DATETIME_PATTERN.length()) {
|
||||
@ -58,7 +59,7 @@ public class PureDateParser extends DefaultDateBasic implements PredicateDatePar
|
||||
return new DateTime(source, DatePattern.PURE_TIME_FORMAT);
|
||||
} else if(length >= 11 && length <= 13){
|
||||
// 时间戳
|
||||
return new DateTime(NumberUtil.parseLong(source));
|
||||
return new DateTime(NumberUtil.parseLong(StrUtil.str(source)));
|
||||
}
|
||||
|
||||
throw new DateException("No pure format fit for date String [{}] !", source);
|
||||
|
@ -57,7 +57,7 @@ public class RFC2822DateParser extends DefaultDateBasic implements PredicateDate
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(final String source) {
|
||||
public DateTime parse(final CharSequence source) {
|
||||
// issue#I9C2D4
|
||||
if(StrUtil.contains(source, ',')){
|
||||
if(StrUtil.contains(source, KEYWORDS_LOCALE_CHINA)){
|
||||
|
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.date.format.parser;
|
||||
|
||||
import org.dromara.hutool.core.date.*;
|
||||
import org.dromara.hutool.core.date.format.DefaultDateBasic;
|
||||
import org.dromara.hutool.core.regex.ReUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 正则日期解析器<br>
|
||||
* 通过定义一个命名分组的正则匹配日期格式,使用正则分组获取日期各部分的值,命名分组使用{@code (?<xxx>子表达式) }表示,如:<br>
|
||||
* <pre>{@code
|
||||
* ^(?<year>\d{4})(?<month>\d{2})$ 匹配 201909
|
||||
* }</pre>
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class RegexDateParser extends DefaultDateBasic implements PredicateDateParser {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int[] NSS = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
|
||||
|
||||
/**
|
||||
* 根据给定带名称的分组正则,创建RegexDateParser
|
||||
*
|
||||
* @param regex 正则表达式
|
||||
* @return RegexDateParser
|
||||
*/
|
||||
public static RegexDateParser of(final String regex) {
|
||||
return new RegexDateParser(Pattern.compile(regex));
|
||||
}
|
||||
|
||||
private final Pattern pattern;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param pattern 正则表达式
|
||||
*/
|
||||
public RegexDateParser(final Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(final CharSequence source) {
|
||||
return ReUtil.isMatch(this.pattern, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(final CharSequence source) throws DateException {
|
||||
final Matcher matcher = this.pattern.matcher(source);
|
||||
if(!matcher.matches()){
|
||||
throw new DateException("Invalid date string: [{}]", source);
|
||||
}
|
||||
|
||||
final DateBuilder dateBuilder = DateBuilder.of();
|
||||
// year
|
||||
final String year = ReUtil.group(matcher, "year");
|
||||
if (StrUtil.isNotEmpty(year)) {
|
||||
dateBuilder.setYear(parseYear(year));
|
||||
}
|
||||
|
||||
// month
|
||||
final String month = ReUtil.group(matcher, "month");
|
||||
if (StrUtil.isNotEmpty(month)) {
|
||||
dateBuilder.setMonth(parseMonth(month));
|
||||
}
|
||||
|
||||
// week
|
||||
final String week = ReUtil.group(matcher, "week");
|
||||
if (StrUtil.isNotEmpty(week)) {
|
||||
dateBuilder.setWeek(parseWeek(week));
|
||||
}
|
||||
|
||||
// day
|
||||
final String day = ReUtil.group(matcher, "day");
|
||||
if (StrUtil.isNotEmpty(day)) {
|
||||
dateBuilder.setDay(parseNumberLimit(day, 1, 31));
|
||||
}
|
||||
|
||||
// hour
|
||||
final String hour = ReUtil.group(matcher, "hour");
|
||||
if (StrUtil.isNotEmpty(hour)) {
|
||||
dateBuilder.setHour(parseNumberLimit(hour, 0, 23));
|
||||
}
|
||||
|
||||
// minute
|
||||
final String minute = ReUtil.group(matcher, "minute");
|
||||
if (StrUtil.isNotEmpty(minute)) {
|
||||
dateBuilder.setMinute(parseNumberLimit(minute, 0, 59));
|
||||
}
|
||||
|
||||
// second
|
||||
final String second = ReUtil.group(matcher, "second");
|
||||
if (StrUtil.isNotEmpty(second)) {
|
||||
dateBuilder.setSecond(parseNumberLimit(second, 0, 59));
|
||||
}
|
||||
|
||||
// ns
|
||||
final String ns = ReUtil.group(matcher, "ns");
|
||||
if (StrUtil.isNotEmpty(ns)) {
|
||||
dateBuilder.setNs(parseNano(ns));
|
||||
}
|
||||
|
||||
// am or pm
|
||||
final String m = ReUtil.group(matcher, "m");
|
||||
if (StrUtil.isNotEmpty(m)) {
|
||||
if ('p' == m.charAt(0)) {
|
||||
dateBuilder.setPm(true);
|
||||
} else {
|
||||
dateBuilder.setAm(true);
|
||||
}
|
||||
}
|
||||
|
||||
// zero zone offset
|
||||
final String zero = ReUtil.group(matcher, "zero");
|
||||
if (StrUtil.isNotEmpty(zero)) {
|
||||
dateBuilder.setZoneOffsetSetted(true);
|
||||
dateBuilder.setZoneOffset(0);
|
||||
}
|
||||
|
||||
// zone offset
|
||||
final String zoneOffset = ReUtil.group(matcher, "zoneOffset");
|
||||
if (StrUtil.isNotEmpty(zoneOffset)) {
|
||||
dateBuilder.setZoneOffsetSetted(true);
|
||||
dateBuilder.setZoneOffset(parseZoneOffset(zoneOffset));
|
||||
}
|
||||
|
||||
// unix时间戳
|
||||
final String unixsecond = ReUtil.group(matcher, "unixsecond");
|
||||
if (StrUtil.isNotEmpty(unixsecond)) {
|
||||
dateBuilder.setUnixsecond(parseLong(unixsecond));
|
||||
}
|
||||
|
||||
// 毫秒时间戳
|
||||
final String millisecond = ReUtil.group(matcher, "millisecond");
|
||||
if (StrUtil.isNotEmpty(millisecond)) {
|
||||
return DateUtil.date(parseLong(millisecond));
|
||||
}
|
||||
|
||||
return dateBuilder.toDate();
|
||||
}
|
||||
|
||||
private static int parseYear(final String year) {
|
||||
final int length = year.length();
|
||||
switch (length) {
|
||||
case 4:
|
||||
return Integer.parseInt(year);
|
||||
case 2:
|
||||
final int num = Integer.parseInt(year);
|
||||
return (num > 50 ? 1900 : 2000) + num;
|
||||
default:
|
||||
throw new DateException("Invalid year: [{}]", year);
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseMonth(final String month) {
|
||||
try {
|
||||
final int monthInt = Integer.parseInt(month);
|
||||
if (monthInt > 0 && monthInt < 13) {
|
||||
return monthInt;
|
||||
}
|
||||
} catch (final NumberFormatException e) {
|
||||
return Month.of(month).getValueBaseOne();
|
||||
}
|
||||
|
||||
throw new DateException("Invalid month: [{}]", month);
|
||||
}
|
||||
|
||||
private static int parseWeek(final String week){
|
||||
return Week.of(week).getIso8601Value();
|
||||
}
|
||||
|
||||
private static int parseNumberLimit(final String numberStr, final int minInclude, final int maxInclude) {
|
||||
try {
|
||||
final int monthInt = Integer.parseInt(numberStr);
|
||||
if (monthInt >= minInclude && monthInt <= maxInclude) {
|
||||
return monthInt;
|
||||
}
|
||||
} catch (final NumberFormatException ignored) {
|
||||
}
|
||||
throw new DateException("Invalid number: [{}]", numberStr);
|
||||
}
|
||||
|
||||
private static long parseLong(final String numberStr) {
|
||||
try {
|
||||
return Long.parseLong(numberStr);
|
||||
} catch (final NumberFormatException ignored) {
|
||||
}
|
||||
throw new DateException("Invalid long: [{}]", numberStr);
|
||||
}
|
||||
|
||||
private static int parseInt(final String numberStr, final int from, final int to) {
|
||||
try {
|
||||
return Integer.parseInt(numberStr.substring(from, to));
|
||||
} catch (final NumberFormatException ignored) {
|
||||
}
|
||||
throw new DateException("Invalid int: [{}]", numberStr);
|
||||
}
|
||||
|
||||
private static int parseNano(final String ns) {
|
||||
return NSS[ns.length() - 1] * Integer.parseInt(ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析时区偏移,类似于'+0800', '+08', '+8:00', '+08:00'
|
||||
* @param zoneOffset 时区偏移
|
||||
* @return 偏移量
|
||||
*/
|
||||
private int parseZoneOffset(final String zoneOffset) {
|
||||
int from = 0;
|
||||
final int to = zoneOffset.length();
|
||||
final boolean neg = '-' == zoneOffset.charAt(from);
|
||||
from++;
|
||||
|
||||
// parse hour
|
||||
final int hour;
|
||||
if (from + 2 <= to && Character.isDigit(zoneOffset.charAt(from + 1))) {
|
||||
hour = parseInt(zoneOffset, from, from + 2);
|
||||
from += 2;
|
||||
} else {
|
||||
hour = parseInt(zoneOffset, from, from + 1);
|
||||
from += 1;
|
||||
}
|
||||
// skip ':' optionally
|
||||
if (from + 3 <= to && zoneOffset.charAt(from) == ':') {
|
||||
from++;
|
||||
}
|
||||
// parse minute optionally
|
||||
int minute = 0;
|
||||
if (from + 2 <= to) {
|
||||
minute = parseInt(zoneOffset, from, from + 2);
|
||||
}
|
||||
return (hour * 60 + minute) * (neg ? -1 : 1);
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ public class RegisterDateParser extends DefaultDateBasic implements DateParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(final String source) throws DateException {
|
||||
public Date parse(final CharSequence source) throws DateException {
|
||||
return parserList
|
||||
.stream()
|
||||
.filter(predicateDateParser -> predicateDateParser.test(source))
|
||||
|
@ -44,7 +44,7 @@ public class TimeParser extends DefaultDateBasic implements PredicateDateParser
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime parse(String source) {
|
||||
public DateTime parse(CharSequence source) {
|
||||
// issue#I9C2D4 处理时分秒
|
||||
//15时45分59秒 修正为 15:45:59
|
||||
source = StrUtil.replaceChars(source, "时分秒", ":");
|
||||
|
@ -166,7 +166,6 @@ public class NumberValidator {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
Integer.decode(s);
|
||||
} catch (final NumberFormatException e) {
|
||||
return false;
|
||||
|
@ -985,4 +985,24 @@ public class ReUtil {
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据提供的匹配器和组名尝试获取匹配的字符串。
|
||||
* <p>
|
||||
* 此方法旨在方便地从匹配器中提取指定名称的组匹配的字符串。如果指定的组不存在,
|
||||
* 则通过捕获异常并返回null来优雅地处理错误。
|
||||
*
|
||||
* @param matcher 匹配器对象,用于查找和匹配文本。
|
||||
* @param name 组的名称,用于指定要提取的匹配字符串的组。
|
||||
* @return 如果找到并成功提取了指定组的匹配字符串,则返回该字符串;如果组不存在,则返回null。
|
||||
*/
|
||||
public static String group(final Matcher matcher, final String name) {
|
||||
try {
|
||||
// 尝试根据组名获取匹配的字符串。
|
||||
return matcher.group(name);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
// 如果组名无效,捕获异常并返回null。
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
package org.dromara.hutool.core.date;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class DateBuilderTest {
|
||||
@Test
|
||||
public void testNormal() {
|
||||
final DateBuilder builder = new DateBuilder();
|
||||
builder.setYear(2019);
|
||||
builder.setMonth(10);
|
||||
builder.setDay(1);
|
||||
final Date date = builder.toDate();
|
||||
|
||||
Assertions.assertEquals("2019-10-01", DateUtil.date(date).toDateStr());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalDateTime() {
|
||||
final DateBuilder builder = DateBuilder.of()
|
||||
.setYear(2019)
|
||||
.setMonth(10)
|
||||
.setDay(1)
|
||||
.setHour(10)
|
||||
.setMinute(20)
|
||||
.setSecond(30)
|
||||
.setNs(900000000)
|
||||
.setZone(TimeZone.getDefault());
|
||||
|
||||
final LocalDateTime dateTime = builder.toLocalDateTime();
|
||||
Assertions.assertEquals("2019-10-01T10:20:30.900", builder.toLocalDateTime().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimestamp() {
|
||||
final String timestamp = "946656000";
|
||||
final DateBuilder dateBuilder = DateBuilder.of().setUnixsecond(Long.parseLong(timestamp));
|
||||
Assertions.assertEquals("2000-01-01T00:00", dateBuilder.toLocalDateTime().toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.dromara.hutool.core.date;
|
||||
|
||||
import org.dromara.hutool.core.lang.Console;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class IssueI8IUTBTest {
|
||||
@Test
|
||||
void parseTest() {
|
||||
final DateTime parse = DateUtil.parse("May 8, 2009 5:57:51 PM");
|
||||
Console.log(parse);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.dromara.hutool.core.date.format.parser;
|
||||
|
||||
import org.dromara.hutool.core.date.DateUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class RegexDateParserTest {
|
||||
@Test
|
||||
void parsePureTest() {
|
||||
final RegexDateParser parser = RegexDateParser.of("^(?<year>\\d{4})(?<month>\\d{2})(?<day>\\d{2})$");
|
||||
final Date parse = parser.parse("20220101");
|
||||
Assertions.assertEquals("2022-01-01", DateUtil.date(parse).toDateStr());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user