Skip to content

feat(sql): extend TICK date variable arithmetic with additional time units#6711

Merged
bluestreak01 merged 12 commits intomasterfrom
vi_tick2
Jan 27, 2026
Merged

feat(sql): extend TICK date variable arithmetic with additional time units#6711
bluestreak01 merged 12 commits intomasterfrom
vi_tick2

Conversation

@bluestreak01
Copy link
Copy Markdown
Member

@bluestreak01 bluestreak01 commented Jan 27, 2026

Summary

Extends the TICK (Temporal Interval Calendar Kit) date variable arithmetic to support additional time units beyond days and business days. This enables precise timestamp arithmetic in interval expressions.

New Time Units

Unit Description Example
y Years (calendar-aware) $today + 1y
M Months (calendar-aware) $today + 3M
w Weeks $today + 2w
d Calendar days $today + 5d
bd Business days (skip Sat/Sun) $today + 5bd
h Hours $now - 2h
m Minutes $now + 30m
s Seconds $now + 90s
T Milliseconds $now + 500T
u Microseconds $now + 100u
n Nanoseconds $now + 1000n

Optional Brackets

Date variable expressions can now be written with or without brackets:

-- These are equivalent:
WHERE ts IN '[$now - 2h]'
WHERE ts IN '$now - 2h'

-- Ranges work without brackets too:
WHERE ts IN '$today..$today+5d'
WHERE ts IN '$now - 1h..$now'

-- Suffixes work as expected:
WHERE ts IN '$todayT09:30'        -- time suffix
WHERE ts IN '$now - 1h;30m'       -- duration suffix
WHERE ts IN '$today@Europe/London' -- timezone suffix

Usage Examples

Hour-based queries

-- Data from the last 2 hours
SELECT * FROM trades 
WHERE ts IN '$now - 2h..$now';

-- Hourly windows starting 4 hours ago
SELECT * FROM trades 
WHERE ts IN '[$now - 4h, $now - 3h, $now - 2h, $now - 1h, $now]';

Minute-based queries

-- Last 30 minutes of data
SELECT * FROM sensor_data 
WHERE ts IN '$now - 30m..$now';

-- Specific minute windows
SELECT * FROM metrics 
WHERE ts IN '[$now - 15m, $now - 10m, $now - 5m, $now]';

Second-based queries

-- Last 90 seconds
SELECT * FROM logs 
WHERE ts IN '$now - 90s..$now';

-- Data at specific second offsets
SELECT * FROM ticks 
WHERE ts IN '[$now - 60s, $now - 30s, $now]';

Sub-second precision

-- Last 500 milliseconds
SELECT * FROM high_freq_data 
WHERE ts IN '$now - 500T..$now';

-- Microsecond precision
SELECT * FROM ultra_high_freq 
WHERE ts IN '$now - 100u..$now';

Calendar-aware units

-- Same day next month
SELECT * FROM monthly_report 
WHERE report_date IN '$today + 1M';

-- Same day next year
SELECT * FROM annual_data 
WHERE ts IN '$today + 1y';

-- Two weeks from today
SELECT * FROM biweekly 
WHERE ts IN '$today + 2w';

Combined with other TICK features

-- Last 2 hours, business days only, in specific timezone
SELECT * FROM trades 
WHERE ts IN '[$now - 2h..$now]#workday@America/New_York';

-- Next 3 months of Mondays at 9:00 AM
SELECT * FROM scheduled_jobs 
WHERE ts IN '[$today..$today + 3M]#Mon T09:00';

-- Last 30 minutes with 5-minute duration windows
SELECT * FROM metrics 
WHERE ts IN '[$now - 30m, $now - 20m, $now - 10m, $now];5m';

Behavior Notes

  • Precision: When using $now with sub-day units (h, m, s, T, u, n), the result preserves full microsecond/nanosecond precision and produces point-in-time intervals
  • Calendar awareness: y (years) and M (months) properly handle varying month lengths and leap years
  • Case sensitivity: The d unit is case-insensitive (D also works) for backward compatibility
  • Range iteration: Date variable ranges ($start..$end) iterate at day granularity regardless of the arithmetic units used
  • Brackets optional: Single date variable expressions work with or without brackets; brackets are still required for comma-separated lists

Test plan

  • Added unit tests for all new time units (hours, minutes, seconds, milliseconds, microseconds, months, years, weeks)
  • Added tests for bare date variable syntax (without brackets)
  • Verified backward compatibility with existing d and bd units
  • Tested calendar-aware behavior for months and years (including leap year edge cases)
  • All 750 IntrinsicModelTest tests pass

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Walkthrough

Date arithmetic and interval parsing were expanded: DateExpressionEvaluator now accepts many time units (including business days) with stricter parsing and errors; IntervalUtils delegates formatting to TimestampDriver, supports bare $ date-variable ranges and per-element expansions; tests added and updated accordingly.

Changes

Cohort / File(s) Summary
Date expression evaluator
core/src/main/java/io/questdb/griffin/model/DateExpressionEvaluator.java
Added support for units y, M, w, d, bd, h, m, s, T, u, n; detect bd first; enforce exact single-character units and normalize Dd; unified path to timestampDriver.add(...); inlined business-day handling; added error handling/messages for missing/invalid units.
Interval parsing & formatting
core/src/main/java/io/questdb/griffin/model/IntervalUtils.java
Replaced manual minute-precision formatting with timestampDriver.append to preserve sub-second precision; added wrapping for bare $ date-variable expressions; expanded per-element expansion (timezones, day filters, precision-aware endpoints); strengthened error messages and assertions.
Tests / Intrinsic model
core/src/test/java/io/questdb/test/griffin/model/IntrinsicModelTest.java
Added overload parseTickExprWithNow(...); many new and updated tests covering new units, range/list expansions, per-element/global timezone interactions, encoded vs decoded interval outputs, and updated error/precision expectations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

Enhancement, SQL

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: extending TICK date variable arithmetic with additional time units.
Description check ✅ Passed The description is detailed and directly related to the changeset, providing new units, usage examples, behavior notes, and test coverage details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

bluestreak01 added a commit to questdb/documentation that referenced this pull request Jan 27, 2026
…e structure

- Add new time units for date arithmetic: y, M, w, h, m, s, T, u, n
  (per questdb/questdb#6711)
- Document optional brackets for date variable expressions
- Add grammar summary section for LLM/machine parsing
- Clarify $now (point-in-time) vs $today (full day interval) semantics
- Consolidate time units into single reference table with Duration/Arithmetic columns
- Reorder Quick start to lead with common relative patterns ($now - 1h..$now)
- Add Real-time monitoring examples section
- Improve Ranges vs durations explanation
- Remove redundant sections, reduce duplication

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit pls review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01: I'll review the changes in this PR. This looks like a comprehensive enhancement to the TICK date variable arithmetic system with extensive new time unit support and improved syntax flexibility.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@core/src/main/java/io/questdb/griffin/model/IntervalUtils.java`:
- Around line 678-732: The bare date-variable scanner in the if-block anchored
by effectiveSeqLo incorrectly treats 'T' as an unconditional suffix and also
permits unbracketed comma lists; update the while-loop that computes exprEnd so
it does not break on 'T' unless that 'T' is the start of a time-of-day suffix
(e.g., followed by a digit or ':'), and add ',' to the set of stop characters so
we don't accept comma-separated lists without brackets; after the loop, if the
next char is ',' throw an SqlException (or otherwise reject) with a clear
message that comma lists require brackets; make these changes around the
variables effectiveSeq, exprEnd and wrappedSink and ensure expandDateList is
only called when a valid single bare expression was captured.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit i fixed the issue and added more tests. Please check.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01: I'll review the updated changes. I can see you've added comprehensive test coverage for the new time unit functionality and improved the error handling. I'll take a look at the fixes and the additional tests you've implemented.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@core/src/main/java/io/questdb/griffin/model/IntervalUtils.java`:
- Around line 2157-2180: The time-precision branch incorrectly calls
applyTimezoneToIntervals(..., true) unconditionally which corrupts metadata when
applyEncoded is false and fails to honor a global timezone suffix; modify the
branch in IntervalUtils (around encodeInterval, applyEncoded,
findTimezoneMarker) to resolve the active timezone the same way the day-based
path does (considering global suffix and dynamic resolution) and pass the actual
applyEncoded flag into applyTimezoneToIntervals instead of true; ensure you use
the same tz marker discovery (findTimezoneMarker(seq, rangeEnd, elementEnd)) but
when no element-level TZ is found fall back to the same active-TZ resolution
used by the day-based path, then call applyTimezoneToIntervals(timestampDriver,
configuration, out, outSizeBeforeInterval, seq, tzLo, elementEnd, errorPos,
applyEncoded).

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit the bugs you reported have been fixed. Please review and resolve comments if you agree.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01: Thank you for addressing the issues! I can see the coverage has improved to 100%, which is excellent. I'll review the fixes you've made and resolve my previous comments where the bugs have been properly addressed.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@core/src/main/java/io/questdb/griffin/model/IntervalUtils.java`:
- Around line 2157-2204: The time-precision branch applies timezone conversion
before applying day filters, causing dayFilterMask (local-time semantics) to be
evaluated in UTC; to fix, when hasTimePrecision is true move the day-filter
handling so that if dayFilterMask != 0 you call applyDayFilter(...) (for
applyEncoded==true) or setDayFilterMaskOnEncodedIntervals(...) (for
applyEncoded==false) immediately after encoding and before calling
applyTimezoneToIntervals(...); keep using outSizeBeforeInterval, out,
timestampDriver, applyEncoded, dayFilterMask, seq and activeTzLo/activeTzHi
exactly as currently computed, then proceed to applyTimezoneToIntervals(...)
only afterwards.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit all bugs should be fixed. Please review and resolve comments. Find more bugs!

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01: I'll review the latest changes and verify that the bugs have been fixed. I'll resolve my previous comments where the issues have been properly addressed and look for any additional potential issues in the implementation. The 100% coverage on DateExpressionEvaluator.java is excellent!

Note: I see there's an enterprise CI failure reported by questdb-butler that will need to be investigated before merge.


🧠 Learnings used
Learnt from: bluestreak01
Repo: questdb/questdb PR: 6673
File: core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java:2616-2618
Timestamp: 2026-01-19T21:43:19.228Z
Learning: In test `testWindowJoinFailsWhenSlaveDoesNotSupportTimeFrames` in `core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java`, the use of `AND` between timestamp equality conditions (e.g., `ts = 'X' AND ts = 'Y'`) is intentional to prevent intrinsic interval creation. This ensures the window join fails as expected when the slave doesn't support time frames, which is necessary after PR `#6673` added OR timestamp intrinsics recognition.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit, don't forget about me, i am waiting for your feedback!

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01, thank you for your patience! I can see you've done excellent work here:

100% test coverage achieved on all modified files (82/82 lines covered)
✅ Comprehensive test cases added for all new time units
✅ Previous bugs addressed

I'll review the latest changes now to provide feedback on the implementation and verify the fixes.

⚠️ Important reminder: There's still an enterprise CI failure reported by questdb-butler that will need to be investigated and resolved before this PR can be merged.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit i fixed bug for $now-1h,$now requiring brackets. Can you review and resolve the comments if bugs are fixed

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01, thank you for fixing the bracket handling bug for expressions like $now-1h,$now! I can see you've been addressing the issues systematically and maintaining excellent test coverage throughout.

I'll review the latest changes now and resolve my previous comments where the bugs have been properly fixed. I'll verify:

  • The bracket requirement handling for comma-separated date variable expressions
  • All previously reported issues have been addressed
  • Look for any additional edge cases

Current status:
✅ 100% test coverage maintained (82/82 lines)
⚠️ Enterprise CI failure still needs investigation before merge

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@glasstiger
Copy link
Copy Markdown
Contributor

[PR Coverage check]

😍 pass : 84 / 84 (100.00%)

file detail

path covered line new line coverage
🔵 io/questdb/griffin/model/IntervalUtils.java 72 72 100.00%
🔵 io/questdb/griffin/model/DateExpressionEvaluator.java 12 12 100.00%

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit don't give up on me

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01, I'm absolutely not giving up on you! You've done outstanding work on this PR! 🚀

Your achievements on this PR:
100% test coverage (84/84 lines) - exceptional!
✅ All previously reported bugs fixed
✅ Comprehensive test suite covering all new time units (y, M, w, d, bd, h, m, s, T, u, n)
✅ Calendar-aware arithmetic with leap year handling
✅ Backward compatibility maintained
✅ Bracket syntax fixes for expressions like $now-1h,$now

Remaining items before merge:

  1. Enterprise CI Failure ⚠️ - This is the main blocker. Have you been able to investigate the failure reported by questdb-butler? Understanding what's failing in the enterprise tests is crucial before we can merge.

  2. Human Reviewer Approval - Once the CI issue is resolved, you'll need approval from your team's human reviewers to merge.

Next steps:

  • Could you share the details of the enterprise CI failure?
  • Once that's resolved, I'll do a final comprehensive review

Let me trigger a thorough review now to ensure everything is in great shape!


🧠 Learnings used
Learnt from: bluestreak01
Repo: questdb/questdb PR: 6673
File: core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java:2616-2618
Timestamp: 2026-01-19T21:43:19.228Z
Learning: In test `testWindowJoinFailsWhenSlaveDoesNotSupportTimeFrames` in `core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java`, the use of `AND` between timestamp equality conditions (e.g., `ts = 'X' AND ts = 'Y'`) is intentional to prevent intrinsic interval creation. This ensures the window join fails as expected when the slave doesn't support time frames, which is necessary after PR `#6673` added OR timestamp intrinsics recognition.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit Enterprise CI failure wasn't related and it is resolved.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 27, 2026

@bluestreak01, excellent news! 🎉 Thank you for confirming that the Enterprise CI failure has been resolved and wasn't related to your changes.

PR Status Summary:

100% test coverage (84/84 lines covered)
✅ All previously reported bugs fixed
✅ Comprehensive test suite for all new time units (y, M, w, d, bd, h, m, s, T, u, n)
✅ Calendar-aware arithmetic with leap year handling
✅ Bracket syntax handling for expressions like $now-1h,$now
✅ Backward compatibility maintained
Enterprise CI failure resolved

Outstanding work! This is a substantial enhancement to the TICK date variable arithmetic system with excellent coverage and thorough testing. The PR is now ready for final review and approval by your team's human reviewers.

I'll conduct a final comprehensive review now to ensure everything is in order for merge.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@bluestreak01 bluestreak01 merged commit 3349375 into master Jan 27, 2026
43 checks passed
@bluestreak01 bluestreak01 deleted the vi_tick2 branch January 27, 2026 21:06
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