Skip to content

[SPARK-57837][SQL] Support the precision argument in current_timestamp(p) and localtimestamp(p) - #57697

Open
stevomitric wants to merge 6 commits into
apache:masterfrom
stevomitric:stevomitric/spark-57837-current-timestamp-precision
Open

[SPARK-57837][SQL] Support the precision argument in current_timestamp(p) and localtimestamp(p)#57697
stevomitric wants to merge 6 commits into
apache:masterfrom
stevomitric:stevomitric/spark-57837-current-timestamp-precision

Conversation

@stevomitric

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This PR adds an optional fractional-seconds precision argument p to current_timestamp(p) / now(p) and localtimestamp(p), mirroring the existing current_time(p). It is part of the umbrella SPARK-56822 (timestamps with nanosecond precision).

  • p == 6 (and the no-argument forms) keep the historical microsecond TIMESTAMP / TIMESTAMP_NTZ types unchanged.
  • p in [7, 9] returns a nanosecond TIMESTAMP_LTZ(p) / TIMESTAMP_NTZ(p), gated behind spark.sql.timestampNanosTypes.enabled.
  • Any other precision is rejected with INVALID_TIMESTAMP_PRECISION, matching the TIMESTAMP(p) type parser (the range check runs before the feature-flag check).

The micro leaf expressions CurrentTimestamp / Now / LocalTimestamp are kept as-is to preserve their rendering and pattern matching; two new placeholder expressions CurrentTimestampNanos / LocalTimestampNanos carry the precision, and CurrentTimestampExpressionBuilder / LocalTimestampExpressionBuilder dispatch on the argument count. ComputeCurrentTime constant-folds the new expressions into query-stable nanosecond literals, just like the microsecond variants.

Why are the changes needed?

ANSI SQL / Foundation defines an optional <timestamp precision> on CURRENT_TIMESTAMP and LOCALTIMESTAMP (Feature F555). This lets users obtain the current time at nanosecond precision when the nanosecond timestamp types are enabled.

Does this PR introduce any user-facing change?

Yes. current_timestamp(p) / now(p) / localtimestamp(p) now accept a precision argument. The no-argument forms are unchanged.

How was this patch tested?

  • Catalyst unit tests: ComputeCurrentTimeSuite (folding, query-stability, precision flooring, time flow) and DateExpressionsSuite (the two expression builders, including the error paths).
  • End-to-end tests in TimestampNanosFunctionsSuiteBase (ANSI on and off): result types, precision flooring, query-stable self-equality, out-of-range precision, and the disabled-flag error.
  • New golden cases in timestamp-ltz-nanos.sql / timestamp-ntz-nanos.sql; regenerated sql-expression-schema.md.

Was this patch authored or co-authored using generative AI tooling?

Co-authored: Claude Code (Claude Opus 4.8)

…p(p) and localtimestamp(p)

### What changes were proposed in this pull request?

This PR adds an optional fractional-seconds precision argument `p` to
`current_timestamp(p)` / `now(p)` and `localtimestamp(p)`, mirroring the existing
`current_time(p)`. It is part of the umbrella SPARK-56822 (timestamps with nanosecond
precision).

- `p == 6` (and the no-argument forms) keep the historical microsecond `TIMESTAMP` /
  `TIMESTAMP_NTZ` types unchanged.
- `p` in `[7, 9]` returns a nanosecond `TIMESTAMP_LTZ(p)` / `TIMESTAMP_NTZ(p)`, gated behind
  `spark.sql.timestampNanosTypes.enabled`.
- Any other precision is rejected with `INVALID_TIMESTAMP_PRECISION`, matching the
  `TIMESTAMP(p)` type parser (the range check runs before the feature-flag check).

The micro leaf expressions `CurrentTimestamp` / `Now` / `LocalTimestamp` are kept as-is to
preserve their rendering and pattern matching; two new placeholder expressions
`CurrentTimestampNanos` / `LocalTimestampNanos` carry the precision, and
`CurrentTimestampExpressionBuilder` / `LocalTimestampExpressionBuilder` dispatch on the argument
count. `ComputeCurrentTime` constant-folds the new expressions into query-stable nanosecond
literals, just like the microsecond variants.

### Why are the changes needed?

ANSI SQL / Foundation defines an optional `<timestamp precision>` on `CURRENT_TIMESTAMP` and
`LOCALTIMESTAMP` (Feature F555). This lets users obtain the current time at nanosecond precision
when the nanosecond timestamp types are enabled.

### Does this PR introduce any user-facing change?

Yes. `current_timestamp(p)` / `now(p)` / `localtimestamp(p)` now accept a precision argument. The
no-argument forms are unchanged.

### How was this patch tested?

- Catalyst unit tests: `ComputeCurrentTimeSuite` (folding, query-stability, precision flooring,
  time flow) and `DateExpressionsSuite` (the two expression builders, including the error paths).
- End-to-end tests in `TimestampNanosFunctionsSuiteBase` (ANSI on and off): result types,
  precision flooring, query-stable self-equality, out-of-range precision, and the disabled-flag
  error.
- New golden cases in `timestamp-ltz-nanos.sql` / `timestamp-ntz-nanos.sql`; regenerated
  `sql-expression-schema.md`.

Co-authored-by: Isaac
…nuous processing

`LocalTimestampNanos` is a standalone `LeafExpression`, not a subclass of
`LocalTimestamp`, so the continuous-processing reject guards in
`ContinuousExecution` and `UnsupportedOperationChecker` -- which match
`_: CurrentTimestampLike | _: CurrentDate | _: LocalTimestamp` -- let
`localtimestamp(p)` slip through, while its LTZ sibling `current_timestamp(p)`
(`CurrentTimestampNanos`, which extends `CurrentTimestampLike`) is correctly
rejected. Add `_: LocalTimestampNanos` to both guards so the nanosecond NTZ
current-time function is rejected consistently with the microsecond and LTZ
forms, and add a `ContinuousSuite` test covering current_timestamp(9) / now(9)
/ localtimestamp(9).

Co-authored-by: Isaac
…tamp(p) to the batch timestamp in micro-batch streaming

In micro-batch streaming, current_timestamp()/localtimestamp() are rewritten
to the replay-stable CurrentBatchTimestamp before the optimizer runs. That
rewrite in MicroBatchExecution only matched the microsecond CurrentTimestamp,
LocalTimestamp, and CurrentDate, so the new CurrentTimestampNanos /
LocalTimestampNanos leaves fell through to ComputeCurrentTime and were folded
to a wall-clock-at-planning literal instead of the batch timestamp -- not
replay-stable across restarts, and diverging from the microsecond form.

Add the two nanosecond leaves to the MicroBatchExecution rewrite and extend
CurrentBatchTimestamp.toLiteral to emit TIMESTAMP_LTZ(p) / TIMESTAMP_NTZ(p)
literals. The batch timestamp is millisecond resolution, so nanos-within-micro
is always 0; TIMESTAMP_LTZ is instant-based and TIMESTAMP_NTZ takes the wall
clock in the session zone, mirroring the existing microsecond branches.

Add a StreamSuite test asserting the collected nanosecond value is
millisecond-aligned, which a wall-clock fold would not satisfy.

Co-authored-by: Isaac
Registering `now` via `CurrentTimestampExpressionBuilder` (annotated
`since = "1.5.0"`, shared with `current_timestamp`) regressed `now`'s
documented version from 1.6.0 to 1.5.0, since `FunctionRegistryBase`
falls back to the builder annotation when no explicit `since` is given.
Pass the original 1.6.0 explicitly at the registration site, mirroring
the `localtime` alias.

Co-authored-by: Isaac
…7837-current-timestamp-precision

# Conflicts:
#	sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ltz-nanos.sql.out
#	sql/core/src/test/resources/sql-tests/analyzer-results/timestamp-ntz-nanos.sql.out
#	sql/core/src/test/resources/sql-tests/inputs/timestamp-ltz-nanos.sql
#	sql/core/src/test/resources/sql-tests/inputs/timestamp-ntz-nanos.sql
#	sql/core/src/test/resources/sql-tests/results/timestamp-ltz-nanos.sql.out
#	sql/core/src/test/resources/sql-tests/results/timestamp-ntz-nanos.sql.out

@uros-b uros-b left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Left a few comments, but otherwise looks good! Thank you @stevomitric

@stevomitric stevomitric changed the title [WIP][SPARK-57837][SQL] Support the precision argument in current_timestamp(p) and localtimestamp(p) [SPARK-57837][SQL] Support the precision argument in current_timestamp(p) and localtimestamp(p) Aug 10, 2026
…x import order

- Prefix the nanosecond `> SELECT current_timestamp(9)` / `localtimestamp(9)`
  examples with `> SET spark.sql.timestampNanosTypes.enabled=true;` so the
  "Documentation generation" job (which runs each example live with the flag
  off) no longer fails with FEATURE_NOT_ENABLED. Matches the convention used
  by DayOfYear / NanosToTimestamp / current_time; add line.contains.tab to the
  scalastyle:off directives for the echo line.
- Reorder the org.apache.spark import in DateExpressionsSuite so SPARK_DOC_ROOT
  comes before SparkUpgradeException, fixing the scalastyle import-order error.

Co-authored-by: Isaac
@stevomitric
stevomitric requested a review from uros-b August 10, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants