{"record":{"id":"01efe7d177597c1d","repo":"hibernate/hibernate-orm","slug":"unsupported-temporal-type-s-01efe7","errorCode":null,"errorMessage":"Unsupported temporal type: %s","messagePattern":"Unsupported temporal type: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/SpannerTruncFunction.java","lineNumber":53,"sourceCode":"\t\t\t\t)\n\t\t);\n\t}\n\n\t@Override\n\tpublic void render(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tList<? extends SqlAstNode> sqlAstArguments,\n\t\t\tReturnableType<?> returnType,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tfinal Expression expression = (Expression) sqlAstArguments.get( 0 );\n\t\tfinal var type = expression.getExpressionType();\n\t\tfinal var temporalType = type != null ? getSqlTemporalType( type ) : null;\n\n\t\tif ( temporalType != null ) {\n\t\t\tswitch ( temporalType ) {\n\t\t\t\tcase DATE -> sqlAppender.appendSql( \"DATE_TRUNC\" );\n\t\t\t\tcase TIMESTAMP, TIME -> sqlAppender.appendSql( \"TIMESTAMP_TRUNC\" );\n\t\t\t\tdefault -> throw new IllegalArgumentException( \"Unsupported temporal type: \" + temporalType );\n\t\t\t}\n\t\t\tsqlAppender.appendSql( \"(\" );\n\t\t\texpression.accept( walker );\n\t\t\tsqlAppender.appendSql( \", \" );\n\t\t\tsqlAstArguments.get( 1 ).accept( walker );\n\t\t\tsqlAppender.appendSql( \")\" );\n\t\t}\n\t\telse {\n\t\t\trenderNumericTrunc( sqlAppender, sqlAstArguments, walker );\n\t\t}\n\t}\n\n\tprivate void renderNumericTrunc(\n\t\t\tSqlAppender sqlAppender,\n\t\t\tList<? extends SqlAstNode> args,\n\t\t\tSqlAstTranslator<?> walker) {\n\t\tsqlAppender.appendSql( \"TRUNC(\" );\n\t\targs.get( 0 ).accept( walker );","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/SpannerTruncFunction.java#L35-L71","documentation":"Spanner's trunc() routing maps DATE to DATE_TRUNC and TIMESTAMP/TIME to TIMESTAMP_TRUNC; other temporal types (offset/zoned timestamps) have no Spanner function and hit the default branch, throwing IllegalArgumentException at render time. A null temporal type falls through to numeric trunc, which is fine.","triggerScenarios":"HQL: trunc(OffsetDateTime-attribute) or trunc(ZonedDateTime-attribute) on the Cloud Spanner dialect.","commonSituations":"Date-bucketing queries (day/week/month rollups) over attributes mapped as offset/zoned types; models ported to Spanner without remapping temporal attributes.","solutions":["Cast the argument: trunc(cast(e.offsetTs as timestamp), MONTH)","Remap the attribute to LocalDateTime for Spanner","Upgrade Hibernate for wider Spanner temporal coverage"],"exampleFix":"// before\nselect trunc(e.offsetTs, MONTH) from Event e\n\n// after\nselect trunc(cast(e.offsetTs as timestamp), MONTH) from Event e","handlingStrategy":"type-guard","validationCode":"// Spanner trunc() only accepts DATE/TIME/TIMESTAMP expressions\nstatic void checkSpannerTruncArg(Class<?> attrType) {\n    if (OffsetDateTime.class.equals(attrType) || ZonedDateTime.class.equals(attrType)\n            || OffsetTime.class.equals(attrType)) {\n        throw new IllegalArgumentException(\"Cast offset/zoned temporals to timestamp for Spanner: \" + attrType);\n    }\n}","typeGuard":"static boolean spannerTemporalSafe(Class<?> t) {\n    return !(OffsetDateTime.class.equals(t) || ZonedDateTime.class.equals(t) || OffsetTime.class.equals(t));\n}","tryCatchPattern":"try {\n    return em.createQuery(hql, Object.class).getResultList();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Unsupported temporal type\")) {\n        return em.createQuery(withTimestampCast(hql), Object.class).getResultList();\n    }\n    throw e;\n}","preventionTips":["Avoid offset/zoned temporal mappings on Spanner entities","Bucket offset timestamps only after an explicit cast to timestamp","Keep a Spanner-dialect integration test for every date-math query"],"tags":["hibernate","spanner","trunc","temporal-type","dialect-limitation"],"backgroundTag":"temporal-type-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}