chinabugotech/hutool · error · IllegalArgumentException

No date time pattern for locale: {}

Error message

No date time pattern for locale: {}

What it means

FormatCache.getPatternForStyle asks the JDK for a localized DateFormat for a style+locale, then casts it to SimpleDateFormat to call toPattern(). If the returned DateFormat is not a SimpleDateFormat (the cast throws ClassCastException), the cache wraps it as IllegalArgumentException with the locale. This means the locale/provider cannot supply a SimpleDateFormat pattern for that style.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java:170

			try {
				DateFormat formatter;
				if (dateStyle == null) {
					formatter = DateFormat.getTimeInstance(timeStyle, locale);
				} else if (timeStyle == null) {
					formatter = DateFormat.getDateInstance(dateStyle, locale);
				} else {
					formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
				}
				pattern = ((SimpleDateFormat) formatter).toPattern();
				final String previous = C_DATE_TIME_INSTANCE_CACHE.putIfAbsent(key, pattern);
				if (previous != null) {
					// even though it doesn't matter if another thread put the pattern
					// it's still good practice to return the String instance that is
					// actually in the ConcurrentMap
					pattern = previous;
				}
			} catch (final ClassCastException ex) {
				throw new IllegalArgumentException("No date time pattern for locale: " + locale);
			}
		}
		return pattern;
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Provide an explicit pattern instead of relying on style-based lookup (use getInstance(pattern) rather than getDateInstance(style, locale)).
  2. Ensure the locale is supported by the active locale provider; avoid locales known to return non-SimpleDateFormat (or special-case them).
  3. Ship full locale data in a custom/jlinked runtime (do not strip jdk.localedata).

Example fix

// before
String p = FastDateFormat.getPatternForStyle(FULL, FULL, new Locale("th","TH"));
// after - supply an explicit pattern
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss", timeZone, locale);
Defensive patterns

Strategy: validation

Validate before calling

boolean localeUsesSimpleDateFormat(Integer dateStyle, Integer timeStyle, Locale l){
  try { return DateFormat.getDateTimeInstance(dateStyle==null?0:dateStyle, timeStyle==null?0:timeStyle, l) instanceof SimpleDateFormat; }
  catch(Exception e){ return false; }
}

Try / catch

try { FastDateFormat.getDateInstance(style, tz, locale); }
catch (IllegalArgumentException e){ if(e.getMessage().contains("No date time pattern for locale")) { locale = Locale.US; } else throw e; }

Prevention

When it happens

Trigger: Requesting a locale/style combo whose DateFormat.getInstance(...) returns a non-SimpleDateFormat implementation. Common with the JRE's Thai Buddhist locale (th_TH) using BuddhistCalendar-backed formats, some compact-number/extended locales, or when a custom LocaleProviderService / SPI is installed.

Common situations: Running with a non-default locale provider (e.g. CLDR vs HOST vs SPI), restricted locales under --limit-features, locales that yield non-Gregorian calendar-backed formats, or jlink'd runtimes missing locale data.

Related errors


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