Skip to content

Conversation

@gokselk
Copy link
Contributor

@gokselk gokselk commented Jan 6, 2026

Which issue does this PR close?

Closes #19117.

Rationale for this change

The to_timestamp function family lacks consistency in supported argument types. While to_timestamp accepts Float64 and Decimal128 types, the related functions (to_timestamp_seconds, to_timestamp_millis, to_timestamp_micros, to_timestamp_nanos) don't offer the same support. Additionally, the documentation claims support for "unsigned integer" types, but this isn't fully implemented.

What changes are included in this PR?

Standardizes all to_timestamp variants to uniformly support:

  • All signed integer types: Int8, Int16, Int32, Int64
  • All unsigned integer types: UInt8, UInt16, UInt32, UInt64
  • Float32 and Float64
  • Decimal128 (for millis/micros/nanos variants)

Are these changes tested?

Yes, added comprehensive SQL logic tests in datafusion/sqllogictest/test_files/datetime/timestamps.slt.

Are there any user-facing changes?

Users can now pass additional numeric types to to_timestamp functions. This is a backward-compatible enhancement.

@github-actions github-actions bot added sqllogictest SQL Logic Tests (.slt) functions Changes to functions implementation labels Jan 6, 2026
Copy link
Contributor

@Jefffrey Jefffrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking this up; I think we should ensure we support Float16 and all the other decimal variants too, for completeness

Comment on lines 404 to 408
Decimal128(_, _) => {
match &args[0] {
ColumnarValue::Scalar(ScalarValue::Decimal128(
Some(value),
_,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was checking the nearby code and found this oddity; we support only scalar decimal128s? thats interesting 🤔

Might be worth correcting this so it works with array types too (like the other arms) and expanding support to the other decimal types for completeness

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be resolved in 8134491.

@Omega359
Copy link
Contributor

Omega359 commented Jan 7, 2026

Thanks for submitting this PR @gokselk, much appreciated.

@gokselk gokselk force-pushed the feat/to-timestamp-args branch from 03c1937 to 1a2facb Compare January 7, 2026 18:41
Comment on lines +458 to +459
Float16 | Float32 | Float64 => {
let arg = args[0].cast_to(&Float64, None)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel each of these can be done natively instead of casting to float64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considered native handling, but Float32 to Float64 cast is lossless and Float16 still needs to be cast to Float64. Single code path is cleaner IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Float16 still needs to be cast to Float64

Could you elaborate on this?

I was mainly hoping to eliminate unnecessary casts where possible since they technically allocate new arrays

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out I was wrong, f16 does implement ArrowNativeTypeOp. Will update to handle all float types natively.

timestamp_nanos as i64
}

fn decimal128_to_timestamp_nanos(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could make this generic over the decimal types to not force the codepaths all through decimal128 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked into this. Decimal32/64 to Decimal128 cast is lossless and cheap, so generic would add complexity without much gain. Happy to change if you see a case where it matters though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice for decimal256 we try to get the i128 value; is there any edge case if it doesn't fit in an i128, or is it not a concern as that value would be too large for timestamp output anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, even i64 nanos caps at around 292 years from epoch. But as_i128() silently truncates, I can add bounds checking for an error instead.

@gokselk gokselk closed this Jan 8, 2026
@gokselk gokselk reopened this Jan 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

functions Changes to functions implementation sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update to_timestamp udf functions to have a consistent set of argument types

4 participants