chinabugotech/hutool · error · ParseException

Unparseable date: {}

Error message

Unparseable date: {}

What it means

The generic parse failure: FastDateParser.parse(String, ParsePosition) returned null because the input string did not match the configured pattern (or could not be fully consumed). The exception carries the original source string and the ParsePosition error index.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java:222

	 */
	private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();

		final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
		init(definingCalendar);
	}

	@Override
	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("Unparseable date: " + source, pp.getErrorIndex());
		}
		return date;
	}

	@Override
	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();

		return parse(source, pos, cal) ? cal.getTime() : null;
	}

	@Override
	public boolean parse(String source, ParsePosition pos, Calendar calendar) {
		final ListIterator<StrategyAndWidth> lt = patterns.listIterator();
		while (lt.hasNext()) {
			final StrategyAndWidth strategyAndWidth = lt.next();

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Align the pattern to the actual input format (verify separators, field lengths, AM/PM markers, timezone tokens).
  2. Normalize/sanitize input before parsing (trim, convert separators).
  3. When multiple formats are possible, try them in sequence or use DateUtil.parse with auto-detection instead of a strict pattern.
  4. Inspect the ParsePosition error index from a lower-level parse call to locate the exact mismatch column.

Example fix

// before
Date d = DateUtil.parse("2024/01/01", "yyyy-MM-dd");
// after
Date d = DateUtil.parse("2024-01-01", "yyyy-MM-dd");
// or align pattern to input:
Date d = DateUtil.parse("2024/01/01", "yyyy/MM/dd");
Defensive patterns

Strategy: try-catch

Validate before calling

void assertMatchesFormat(String src, String pattern){
  try { new SimpleDateFormat(pattern).parse(src); } catch (ParseException e){ throw new IllegalArgumentException("source does not match "+pattern+" at col "+e.getErrorOffset()); }
}

Try / catch

try { d = DateUtil.parse(source, pattern); }
catch (Exception e) { log.warn("bad date '{}', using null", source); d = null; }

Prevention

When it happens

Trigger: Calling DateUtil.parse(source, pattern) where source does not conform to pattern; partial matches (e.g. pattern 'yyyy-MM-dd' against '2024/01/01'); trailing characters; non-numeric tokens where numbers expected; out-of-range values (month 13, hour 25).

Common situations: Mismatched separators (- vs /), wrong field order, user-typed input, data exported from another system with a different default format, daylight-saving/timezone edge cases producing invalid local times.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/589d159ab8176d20. Report an issue: GitHub.