{"record":{"id":"21690ee9b2737233","repo":"apache/iceberg","slug":"expected-value-to-be-date-or-timestamp-valuetyp-21690e","errorCode":null,"errorMessage":"Expected value to be date or timestamp: ${valueType.catalogString()}","messagePattern":"Expected value to be date or timestamp: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/functions/DaysFunction.java","lineNumber":48,"sourceCode":"import org.apache.spark.sql.types.TimestampType;\n\n/**\n * A Spark function implementation for the Iceberg day transform.\n *\n * <p>Example usage: {@code SELECT system.days('source_col')}.\n */\npublic class DaysFunction extends UnaryUnboundFunction {\n\n  @Override\n  protected BoundFunction doBind(DataType valueType) {\n    if (valueType instanceof DateType) {\n      return new DateToDaysFunction();\n    } else if (valueType instanceof TimestampType) {\n      return new TimestampToDaysFunction();\n    } else if (valueType instanceof TimestampNTZType) {\n      return new TimestampNtzToDaysFunction();\n    } else {\n      throw new UnsupportedOperationException(\n          \"Expected value to be date or timestamp: \" + valueType.catalogString());\n    }\n  }\n\n  @Override\n  public String description() {\n    return name()\n        + \"(col) - Call Iceberg's day transform\\n\"\n        + \"  col :: source column (must be date or timestamp)\";\n  }\n\n  @Override\n  public String name() {\n    return \"days\";\n  }\n\n  protected abstract static class BaseToDaysFunction extends BaseScalarFunction<Integer>\n      implements ReducibleFunction<Integer, Integer> {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/functions/DaysFunction.java#L30-L66","documentation":"Iceberg's days() transform function binds its single argument at planning time. Only DATE, TIMESTAMP, and TIMESTAMP_NTZ columns have a defined day-granularity transform; any other type is rejected with UnsupportedOperationException that includes the offending type's catalog string.","triggerScenarios":"Calling iceberg.days(col) where col is STRING, INT, BIGINT, or any non-temporal type — e.g. days(event_time_str) where event_time_str is a string timestamp.","commonSituations":"Passing a string-formatted timestamp stored as VARCHAR; passing a unix epoch BIGINT column assuming it works like Spark's to_date; calling days() on a date string column from an external source.","solutions":["Cast the column to TIMESTAMP or DATE first: days(cast(ts_str AS TIMESTAMP)).","For epoch-seconds BIGINT, convert: days(timestamp_seconds(epoch_col)).","Use to_date() on the string column before applying days(): days(to_date(ts_str))."],"exampleFix":"// before\nSELECT iceberg.days(ts_string) FROM t;\n// after\nSELECT iceberg.days(CAST(ts_string AS TIMESTAMP)) FROM t;","handlingStrategy":"type-guard","validationCode":"require(Seq(DateType, TimestampType, TimestampNTZType).exists(_.acceptsType(col.dataType)),\n  s\"days() requires date/timestamp, got ${col.dataType}\")","typeGuard":"def isTemporalForDays(t: DataType): Boolean =\n  t == DateType || t == TimestampType || t == TimestampNTZType","tryCatchPattern":null,"preventionTips":["Store timestamps as TIMESTAMP, not STRING, when you plan to use Iceberg transforms","Convert epoch BIGINT columns with timestamp_seconds()/timestamp_millis() first"],"tags":["spark","sql-function-binding","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-23T08:17:48.524Z"}