This commit is contained in:
Looly 2021-09-28 00:07:13 +08:00
parent 75d84b4768
commit 9642fa8862
7 changed files with 71 additions and 45 deletions

View File

@ -2,6 +2,7 @@ package cn.hutool.core.date;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.FastDateParser;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.util.ObjectUtil;
@ -695,4 +696,21 @@ public class CalendarUtil {
throw new DateException("Unable to parse the date: {}", str);
}
/**
* 使用指定{@link DateParser}解析字符串为{@link Calendar}
*
* @param str 日期字符串
* @param lenient 是否宽容模式
* @param parser {@link DateParser}
* @return 解析后的 {@link Calendar}解析失败返回{@code null}
* @since 5.7.14
*/
public static Calendar parse(CharSequence str, boolean lenient, DateParser parser) {
final Calendar calendar = Calendar.getInstance(parser.getTimeZone(), parser.getLocale());
calendar.clear();
calendar.setLenient(lenient);
return parser.parse(StrUtil.str(str), new ParsePosition(0), calendar) ? calendar : null;
}
}

View File

@ -287,7 +287,7 @@ public class DateTime extends Date {
* @see DatePattern
*/
public DateTime(CharSequence dateStr, DateParser dateParser) {
this(parse(dateStr, dateParser), dateParser.getTimeZone());
this(parse(dateStr, dateParser));
}
// -------------------------------------------------------------------- Constructor end
@ -1019,14 +1019,15 @@ public class DateTime extends Date {
* @param parser {@link FastDateFormat}
* @return {@link Date}
*/
private static Date parse(CharSequence dateStr, DateParser parser) {
private static Calendar parse(CharSequence dateStr, DateParser parser) {
Assert.notNull(parser, "Parser or DateFromat must be not null !");
Assert.notBlank(dateStr, "Date String must be not blank !");
try {
return parser.parse(dateStr.toString());
} catch (Exception e) {
throw new DateException("Parse [{}] with format [{}] error!", dateStr, parser.getPattern(), e);
final Calendar calendar = CalendarUtil.parse(dateStr, true, parser);
if (null == calendar) {
throw new DateException("Parse [{}] with format [{}] error!", dateStr, parser.getPattern());
}
return calendar;
}
/**

View File

@ -33,8 +33,8 @@ public interface DateParser extends DateBasic{
Date parse(String source, ParsePosition pos);
/**
* 根据给定格式转换日期字符串
* Updates the Calendar with parsed fields. Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed.
* 根据给定格式更新{@link Calendar}
* Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed.
* Not all source text needs to be consumed.
* Upon parse failure, ParsePosition error index is updated to the offset of the source text which does not match the supplied format.
*
@ -49,20 +49,24 @@ public interface DateParser extends DateBasic{
/**
* 将日期字符串解析并转换为 {@link Date} 对象<br>
*
* @param source A <code>String</code> whose beginning should be parsed.
* @return a <code>java.util.Date</code> object
* @param source A {@code String} whose beginning should be parsed.
* @return a {@code java.util.Date} object
* @throws ParseException if the beginning of the specified string cannot be parsed.
* @see java.text.DateFormat#parseObject(String)
*/
Object parseObject(String source) throws ParseException;
default Object parseObject(String source) throws ParseException{
return parse(source);
}
/**
* 根据 {@link ParsePosition} 给定将日期字符串解析并转换为 {@link Date} 对象<br>
*
* @param source A <code>String</code> whose beginning should be parsed.
* @param source A {@code String} whose beginning should be parsed.
* @param pos the parse position
* @return a <code>java.util.Date</code> object
* @return a {@code java.util.Date} object
* @see java.text.DateFormat#parseObject(String, ParsePosition)
*/
Object parseObject(String source, ParsePosition pos);
default Object parseObject(String source, ParsePosition pos){
return parse(source, pos);
}
}

View File

@ -220,18 +220,14 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
}
@Override
public Object parseObject(final String source) throws ParseException {
return parse(source);
}
@Override
public Date parse(final String source) throws ParseException {
public Date parse(String source) throws ParseException {
final ParsePosition pp = new ParsePosition(0);
final Date date = parse(source, pp);
if (date == null) {
// Add a note re supported date range
if (locale.equals(JAPANESE_IMPERIAL)) {
throw new ParseException("(The " + locale + " locale does not support dates before 1868 AD)\n" + "Unparseable date: \"" + source, pp.getErrorIndex());
throw new ParseException("(The " + locale + " locale does not support dates before 1868 AD)\n" +
"Unparseable date: \"" + source, pp.getErrorIndex());
}
throw new ParseException("Unparseable date: " + source, pp.getErrorIndex());
}
@ -239,12 +235,7 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
}
@Override
public Object parseObject(final String source, final ParsePosition pos) {
return parse(source, pos);
}
@Override
public Date parse(final String source, final ParsePosition pos) {
public Date parse(String source, ParsePosition pos) {
// timing tests indicate getting new instance is 19% faster than cloning
final Calendar cal = Calendar.getInstance(timeZone, locale);
cal.clear();
@ -253,12 +244,12 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
}
@Override
public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
public boolean parse(String source, ParsePosition pos, Calendar calendar) {
final ListIterator<StrategyAndWidth> lt = patterns.listIterator();
while (lt.hasNext()) {
final StrategyAndWidth strategyAndWidth = lt.next();
final int maxWidth = strategyAndWidth.getMaxWidth(lt);
if (!strategyAndWidth.strategy.parse(this, calendar, source, pos, maxWidth)) {
if (false == strategyAndWidth.strategy.parse(this, calendar, source, pos, maxWidth)) {
return false;
}
}
@ -500,9 +491,6 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
this.formatField = formatField;
}
/**
* {@inheritDoc}
*/
@Override
boolean isNumber() {
return false;
@ -575,9 +563,6 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
this.field = field;
}
/**
* {@inheritDoc}
*/
@Override
boolean isNumber() {
return true;
@ -637,9 +622,6 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
}
private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) {
/**
* {@inheritDoc}
*/
@Override
int modify(final FastDateParser parser, final int iValue) {
return iValue < 100 ? parser.adjustYear(iValue) : iValue;
@ -726,9 +708,6 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
createPattern(sb);
}
/**
* {@inheritDoc}
*/
@Override
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
if (value.charAt(0) == '+' || value.charAt(0) == '-') {
@ -759,9 +738,6 @@ public class FastDateParser extends AbstractDateBasic implements DateParser {
createPattern(pattern);
}
/**
* {@inheritDoc}
*/
@Override
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
if (Objects.equals(value, "Z")) {

View File

@ -4,15 +4,26 @@ import org.junit.Assert;
import org.junit.Test;
import java.util.Calendar;
import java.util.Objects;
public class CalendarUtilTest {
@Test
public void formatChineseDate(){
Calendar calendar = DateUtil.parse("2018-02-24 12:13:14").toCalendar();
Calendar calendar = Objects.requireNonNull(DateUtil.parse("2018-02-24 12:13:14")).toCalendar();
final String chineseDate = CalendarUtil.formatChineseDate(calendar, false);
Assert.assertEquals("二〇一八年二月二十四日", chineseDate);
final String chineseDateTime = CalendarUtil.formatChineseDate(calendar, true);
Assert.assertEquals("二〇一八年二月二十四日一十二时一十三分一十四秒", chineseDateTime);
}
@Test(expected = IllegalArgumentException.class)
public void parseTest(){
final Calendar calendar = CalendarUtil.parse("2021-09-27 00:00:112323", false,
DatePattern.NORM_DATETIME_FORMAT);
// https://github.com/dromara/hutool/issues/1849
// 在使用严格模式时秒不正确抛出异常
DateUtil.date(calendar);
}
}

View File

@ -1,5 +1,6 @@
package cn.hutool.core.date;
import cn.hutool.core.lang.Console;
import org.junit.Assert;
import org.junit.Test;
@ -131,4 +132,11 @@ public class DateTimeTest {
//跨年的周返回的总是1
Assert.assertEquals(1, date.weekOfYear());
}
@Test
public void ofTest(){
String a = "2021-09-27 00:00:99";
final DateTime dateTime = new DateTime(a, DatePattern.NORM_DATETIME_FORMAT);
Console.log(dateTime);
}
}

View File

@ -183,4 +183,12 @@ public class CsvReaderTest {
Assert.assertEquals("456", row.get(1));
Assert.assertEquals("'789;0'abc", row.get(2));
}
@Test
public void readDisableCommentTest(){
final CsvReader reader = CsvUtil.getReader(CsvReadConfig.defaultConfig().disableComment());
final CsvData read = reader.read(ResourceUtil.getUtf8Reader("test.csv"));
final CsvRow row = read.getRow(0);
Assert.assertEquals("# 这是一行注释,读取时应忽略", row.get(0));
}
}