hibernate/hibernate-orm · error · HibernateException

could not parse timestamp string %s

Error message

could not parse timestamp string %s

What it means

OffsetDateTimeJavaType.fromEncodedString() parses the text Hibernate stored for OffsetDateTime on databases without full timezone support. PARSE_FORMATTER accepts ISO_LOCAL_DATE_TIME with an optional offset ('+HH:MM:ss' or 'Z'); if no offset is present the value is assumed UTC. Text with a space separator, compact offsets like '+0100', trailing characters, or a bare date fails DateTimeParseException and is rethrown as HibernateException("could not parse timestamp string ...").

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/OffsetDateTimeJavaType.java:118

	}

	@Override
	public OffsetDateTime fromString(CharSequence string) {
		return OffsetDateTime.from( ISO_OFFSET_DATE_TIME.parse( string ) );
	}

	@Override
	public OffsetDateTime fromEncodedString(CharSequence charSequence, int start, int end) {
		try {
			final var temporalAccessor = PARSE_FORMATTER.parse( subSequence( charSequence, start, end ) );
			return temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS )
					? OffsetDateTime.from( temporalAccessor )
					// For databases that don't have timezone support,
					// we encode timestamps at UTC, so allow parsing
					: LocalDateTime.from( temporalAccessor ).atOffset( ZoneOffset.UTC );
		}
		catch ( DateTimeParseException pe) {
			throw new HibernateException( "could not parse timestamp string "
						+ subSequence( charSequence, start, end ), pe );
		}
	}

	@Override
	public <X> X unwrap(OffsetDateTime offsetDateTime, Class<X> type, WrapperOptions options) {
		if ( offsetDateTime == null ) {
			return null;
		}

		if ( OffsetDateTime.class.isAssignableFrom( type ) ) {
			return type.cast( offsetDateTime );
		}

		if ( ZonedDateTime.class.isAssignableFrom( type ) ) {
			return type.cast( offsetDateTime.toZonedDateTime() );
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Re-encode the stored text to ISO local date-time with optional numeric offset ('2024-12-31T10:15:30' or '...+01:00')
  2. Prefer a native TIMESTAMP_WITH_TIMEZONE column and TimeZoneStorageType.NATIVE where the dialect supports it
  3. Keep hibernate.timezone.default_storage identical between the code that wrote and reads the data; rewrite data when it changes
  4. Add an AttributeConverter for the affected attribute that parses the actual legacy format

Example fix

// before: encoded column holds '2024-12-31 10:15:30 +01:00'
// load -> HibernateException: could not parse timestamp string ...

// after
UPDATE meetings SET ts_text = REPLACE(ts_text, ' ', 'T');
-- '2024-12-31T10:15:30+01:00' parses (space only between date/time removed; offset kept compact fails -> use +01:00 form)
Defensive patterns

Strategy: validation

Validate before calling

static final java.time.format.DateTimeFormatter F = new java.time.format.DateTimeFormatterBuilder()
    .append(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    .optionalStart().appendOffset("+HH:MM:ss", "Z").optionalEnd().toFormatter();

static boolean isParsableOffsetDateTimeText(CharSequence s) {
    try { F.parse(s); return true; } catch (java.time.format.DateTimeParseException e) { return false; }
}

Type guard

static java.time.OffsetDateTime tryOffsetDateTime(String s) {
    try { return java.time.OffsetDateTime.parse(s); } catch (Exception e) { return null; }
}

Try / catch

catch (HibernateException e) {
    if (e.getCause() instanceof DateTimeParseException)
        throw new IllegalArgumentException("Stored timestamp text is not ISO date-time[offset]: '" + text + "'", e);
    throw e;
}

Prevention

When it happens

Trigger: Dialect without native timezone support stores OffsetDateTime as text and the column content is not ISO-8601 (space separator, 'Z' variants like 'UTC'); changing hibernate.timezone.default_storage (e.g. NORMAL vs NORMALIZE_UTC) after data was written so the read format no longer matches; rows imported from CSV with re-formatted timestamps

Common situations: Migrating between databases with different timestamptz handling; storage-strategy configuration changes without data rewrite; hand-edited or externally loaded timestamp text

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/52800dacb3d5a666. Report an issue: GitHub.