{"record":{"id":"2ba2502b8330dbf2","repo":"apache/iceberg","slug":"expected-value-to-be-timestamp-valuetype-catalo","errorCode":null,"errorMessage":"Expected value to be timestamp: ${valueType.catalogString()}","messagePattern":"Expected value to be timestamp: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/functions/HoursFunction.java","lineNumber":43,"sourceCode":"import org.apache.spark.sql.types.DataTypes;\nimport org.apache.spark.sql.types.TimestampNTZType;\nimport org.apache.spark.sql.types.TimestampType;\n\n/**\n * A Spark function implementation for the Iceberg hour transform.\n *\n * <p>Example usage: {@code SELECT system.hours('source_col')}.\n */\npublic class HoursFunction extends UnaryUnboundFunction {\n\n  @Override\n  protected BoundFunction doBind(DataType valueType) {\n    if (valueType instanceof TimestampType) {\n      return new TimestampToHoursFunction();\n    } else if (valueType instanceof TimestampNTZType) {\n      return new TimestampNtzToHoursFunction();\n    } else {\n      throw new UnsupportedOperationException(\n          \"Expected value to be timestamp: \" + valueType.catalogString());\n    }\n  }\n\n  @Override\n  public String description() {\n    return name()\n        + \"(col) - Call Iceberg's hour transform\\n\"\n        + \"  col :: source column (must be timestamp)\";\n  }\n\n  @Override\n  public String name() {\n    return \"hours\";\n  }\n\n  public static class TimestampToHoursFunction extends BaseScalarFunction<Integer> {\n    // magic method used in codegen","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/functions/HoursFunction.java#L25-L61","documentation":"The hours() SQL catalog function accepts only timestamp (or timestamp_ntz) values since hour extraction is defined on instants. Any other type, including DATE, fails bind with UnsupportedOperationException naming the actual type.","triggerScenarios":"Calling system.hours(col) where col is DATE, string, or another non-timestamp type.","commonSituations":"Passing a date column to hours() (a date has no hour component); passing string timestamps without casting; mixing up days()/hours() functions.","solutions":["Cast date to timestamp if an implicit midnight hour is intended: system.hours(CAST(d AS TIMESTAMP))","Use system.days() for DATE columns instead","Cast string values to TIMESTAMP before calling hours()"],"exampleFix":"// before\nspark.sql(\"SELECT system.hours(event_date) FROM tbl\") -- event_date is DATE\n// after\nspark.sql(\"SELECT system.days(event_date) FROM tbl\")","handlingStrategy":"type-guard","validationCode":"// hours() requires timestamp-like types\nboolean hoursOk(DataType t) { return t instanceof TimestampType || t instanceof TimestampNTZType; }","typeGuard":"boolean hoursOk(DataType t) { return t instanceof TimestampType || t instanceof TimestampNTZType; }","tryCatchPattern":null,"preventionTips":["Use days()/months()/years() for DATE columns, hours() only for timestamps","Cast DATE to TIMESTAMP only when an hour component is meaningful","Validate input column types in generated SQL pipelines"],"tags":["spark","sql-functions","temporal","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}