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
- Provide an explicit pattern instead of relying on style-based lookup (use getInstance(pattern) rather than getDateInstance(style, locale)).
- Ensure the locale is supported by the active locale provider; avoid locales known to return non-SimpleDateFormat (or special-case them).
- 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
- Prefer explicit patterns over style-based lookups for non-Gregorian locales.
- Do not strip jdk.localedata in jlinked runtimes.
- Document which locales your app supports for date formatting.
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
- (The {} locale does not support dates before 1868 AD) Unpars
- Parse [{}] with format [{}] error!
- Unterminated quote
- Unparseable date: {}
- Format '{}' not supported
AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14).
Data as JSON: /api/errors/79f20901e13fa60a.
Report an issue: GitHub.