hibernate/hibernate-orm · error · HibernateException
could not parse time string %s
Error message
could not parse time string %s
What it means
JdbcTimeJavaType.fromString() parses time text with DateTimeFormatter.ISO_LOCAL_TIME, which requires 24-hour HH:mm:ss (fractional seconds allowed). Any other shape - 12-hour clock with AM/PM, missing seconds, trailing spaces, empty string - throws DateTimeParseException, rethrown as HibernateException("could not parse time string ..."). This path is used for HQL time literals and string-to-Time conversion.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JdbcTimeJavaType.java:259
: LocalTime.ofInstant( value.toInstant(), ZoneOffset.systemDefault() );
}
@Override
public String toString(Time value) {
return LITERAL_FORMATTER.format( fromDate( value ) );
}
@Override
public Time fromString(CharSequence string) {
try {
final var temporalAccessor = LITERAL_FORMATTER.parse( string );
final var localTime = LocalTime.from( temporalAccessor );
final var time = Time.valueOf( localTime );
time.setTime( time.getTime() + localTime.getNano() / 1_000_000 );
return time;
}
catch ( DateTimeParseException pe) {
throw new HibernateException( "could not parse time string " + string, pe );
}
}
@Override
public Time fromEncodedString(CharSequence charSequence, int start, int end) {
try {
final var temporalAccessor = ENCODED_FORMATTER.parse( subSequence( charSequence, start, end ) );
return Time.valueOf( temporalAccessor.query( LocalTime::from ) );
}
catch ( DateTimeParseException pe) {
throw new HibernateException( "could not parse time string " + subSequence( charSequence, start, end ), pe );
}
}
@Override
public void appendEncodedString(SqlAppender sb, Time value) {
LITERAL_FORMATTER.formatTo( fromDate( value ), sb );
}View on GitHub (pinned to fad1729dce)
Solutions
- Convert times to 24-hour HH:mm:ss before binding or storing
- Use typed parameters (LocalTime or java.sql.Time) instead of string literals in queries
- Add an AttributeConverter that parses the legacy 12-hour format with a matching formatter
- Trim inputs and validate with LocalTime.parse before persisting
Example fix
// before
em.createQuery("select s from Shift s where s.begin = '3:04 PM'") // HibernateException
// after
em.createQuery("select s from Shift s where s.begin = '15:04:05'")
// or: query.setParameter("begin", LocalTime.of(15,4,5)); Defensive patterns
Strategy: validation
Validate before calling
static boolean isIsoTime(CharSequence s) {
try { java.time.LocalTime.parse(s); return true; }
catch (java.time.format.DateTimeParseException e) { return false; }
}
if (!isIsoTime(text.trim())) throw new IllegalArgumentException("Expected HH:mm:ss: " + text); Type guard
static java.time.LocalTime tryIsoTime(String s) {
try { return java.time.LocalTime.parse(s.trim()); } catch (Exception e) { return null; }
} Try / catch
try { Time t = JdbcTimeJavaType.INSTANCE.fromString(text); }
catch (HibernateException e) {
if (e.getCause() instanceof DateTimeParseException)
throw new IllegalArgumentException("Bad time text: '" + text + "' (expected HH:mm:ss)", e);
throw e;
} Prevention
- Convert 12-hour picker output to 24-hour HH:mm:ss at the UI boundary
- Bind LocalTime/java.sql.Time parameters, not strings
- Trim and validate time strings in DTO validation before they reach persistence
When it happens
Trigger: HQL literal like ... where e.start = '3:04 PM' or '10:15' (only '15:04:05' or '15:04:05.123' parse); fromString called with data exported from UI time pickers using 12-hour format; a String value coerced into a java.sql.Time attribute.
Common situations: Front-end time pickers producing 'h:mm a' strings; CSV/Excel imports with times like '3:04:05 PM'; locale-formatted time strings bound as literals in JPQL.
Related errors
- could not parse date string %s
- could not parse timestamp string %s
- Insert conflict 'do update' clause with constraint name is n
- field type not supported on Derby: " + unit
- format() function not supported on Derby
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/8d873a4cc64695a2.
Report an issue: GitHub.