diff --git a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java index 001c1b11c..cb9aa732f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java @@ -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; + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java index 1fb76da0f..cdb79e618 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java @@ -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; } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java index db4f520d7..5668f579f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/DateParser.java @@ -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} 对象
* - * @param source A String whose beginning should be parsed. - * @return a java.util.Date 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} 对象
* - * @param source A String whose beginning should be parsed. + * @param source A {@code String} whose beginning should be parsed. * @param pos the parse position - * @return a java.util.Date 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); + } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java index 88f6385f5..e0ddfbc84 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java @@ -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 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")) { diff --git a/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java index 79920e5e6..63e7fc7f9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/CalendarUtilTest.java @@ -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); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateTimeTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateTimeTest.java index 3a0724cc1..bf856d611 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateTimeTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateTimeTest.java @@ -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); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/text/csv/CsvReaderTest.java b/hutool-core/src/test/java/cn/hutool/core/text/csv/CsvReaderTest.java index 908f1c5c5..d21bf9c3b 100644 --- a/hutool-core/src/test/java/cn/hutool/core/text/csv/CsvReaderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/text/csv/CsvReaderTest.java @@ -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)); + } }