HI Yuan Tian Thanks for the clarification. We will proceed with the implementation based on these semantics. In particular, we will keep only the existing mo/y Tree SQL units, use the boundary-anchored duration-vector formula, implement provable duration comparisons without flattening calendar months, preserve legacy CQ behavior, and ensure recovery always derives occurrences from the original boundary using a persisted occurrence index or equivalent information. We will also define calendarApply as applying calendar months in the persisted ZoneId first and fixed ticks second. Best, Bryan Yang
Yuan Tian <[email protected]> 于2026年8月11日周二 09:49写道: > Hi Bryan, > > Thanks for the detailed proposal. I agree with the overall direction of > representing calendar months and fixed elapsed time separately. My > preferences for the five questions are: > > 1. > > When a calendar-based EVERY omits BOUNDARY, it should align to > 1970-01-01 > 00:00:00 in the persisted CQ ZoneId. An explicit BOUNDARY 0 should > continue to mean the Unix epoch instant. Fixed-only EVERY intervals > should > retain their existing default behavior. > 2. > > RANGE should use the boundary-anchored duration-vector formula. This > preserves the invariant that, when RANGE == EVERY, the window start is > exactly the previous scheduled occurrence. Subtracting an offset from an > already-clamped execution timestamp is unsafe because calendar-month > arithmetic is not reversible. > 3. > > Comparisons whose ordering depends on the month, time zone, or DST—such > as 1mo versus 30d—should be rejected rather than flattened to an > approximate duration. However, compound durations should not be rejected > merely because they contain both components. Comparisons that can be > proven, such as 1mo3d being greater than 1mo, may still be accepted. > 4. > > Existing persisted mo/y CQs should retain their legacy fixed-duration > behavior. Old metadata should not be re-parsed and silently migrated. > Recreating the CQ provides a clear way for users to opt into calendar > semantics. > 5. > > For this change, I suggest keeping the existing Tree SQL abbreviations > mo/y. CQ currently uses the Tree SQL grammar, whose duration literals do > not support the full month/year forms. Although Table SQL accepts > MONTH/YEAR, CQ is not supported in the Table dialect yet. Full unit > aliases would be better handled as a separate, consistent Tree SQL > grammar > enhancement covering GROUP BY TIME, date arithmetic, FILL/SESSION, and > CQ, > rather than as CQ-only aliases. > > I would also suggest explicitly defining calendarApply as applying calendar > months in the persisted ZoneId first and fixed ticks second. Persisting the > occurrence index, or equivalent information, would help ensure that > recovery and leader changes always calculate occurrences from the original > boundary. > > Best regards, > ---------------------------- > > Yuan Tian > > On Mon, Aug 10, 2026 at 2:50 PM Bryan Yang <[email protected]> wrote: > > > Hi IoTDB community, > > > > I would like to share our current thoughts and proposal for supporting > > calendar-month and calendar-year intervals in Continuous Query (CQ). The > > related issue is: > > > > https://github.com/apache/iotdb/issues/18428 > > > > Currently, CQ accepts mo/y in EVERY and RANGE, but converts them into > fixed > > durations: one month becomes 30 days and one year becomes 365 days. This > > causes scheduling drift and may make the CQ cadence inconsistent with > GROUP > > BY(1mo), which already uses natural calendar-month semantics. > > > > Our proposal is to treat calendar duration as first-class CQ metadata > > throughout parsing, RPC, persistence, recovery, and scheduling. > > > > Proposed user-visible behavior: > > > > - Support mo/month and y/year in CQ EVERY and RANGE. > > - Normalize 1y to 12 calendar months. > > - Keep w, d, h, m, s, ms, us, and ns as fixed elapsed-time units. > > - Continue supporting compound durations such as 1y2mo3d. > > - If EVERY is omitted, inherit the complete duration from GROUP BY > TIME. > > Therefore, GROUP BY(1mo) should produce calendar EVERY 1mo rather than > > fixed 30d. > > - If RANGE is omitted, keep the existing defaults: > > - startOffset = EVERY > > - endOffset = 0 > > - This feature does not change the data types, aggregation functions, > or > > SELECT INTO rules supported by the CQ query body. > > > > Logically, a duration would contain two components: > > > > Duration { > > monthPart: integer number of calendar months > > fixedPart: fixed ticks in the configured timestamp precision > > } > > > > Calendar scheduling should always be calculated from the original > BOUNDARY. > > > > For boundary B, EVERY duration E, CQ time zone Z, and occurrence index n: > > > > executionTime(n) = calendarApply(B, n * E, Z) > > > > This is important for month-end anchors. For example: > > > > BOUNDARY 2024-01-31 > > EVERY 1mo > > > > should produce: > > > > 2024-01-31 > > 2024-02-29 > > 2024-03-31 > > 2024-04-30 > > > > It should not repeatedly add one month to the previously clamped > timestamp, > > because that would drift to March 29. > > > > For RANGE, we propose applying the offset in duration-vector space: > > > > startTime(n) = calendarApply(B, n * E - startOffset, Z) > > endTime(n) = calendarApply(B, n * E - endOffset, Z) > > > > This preserves the existing documented BOUNDARY formula and ensures that > > EVERY 1mo RANGE 1mo produces contiguous windows, including for Jan-31 and > > Feb-29 anchors. > > > > Calendar arithmetic should use the session ZoneId captured when the CQ is > > created and persisted with its metadata. Month-end dates should clamp to > > the last valid day of the target month: > > > > 2023-01-31 + 1mo = 2023-02-28 > > 2024-01-31 + 1mo = 2024-02-29 > > 2020-02-29 + 1y = 2021-02-28 > > 2020-02-29 + 4y = 2024-02-29 > > > > For TIMEOUT POLICY: > > > > - BLOCKED should execute every occurrence in order, even when late. > The > > query window should be based on the scheduled occurrence time rather > > than > > the actual wall-clock start time. > > - DISCARD should skip missed occurrences and jump directly to the > first > > valid occurrence not earlier than the current time. > > - Calendar occurrence lookup should use estimation plus correction or > > binary search instead of iterating month by month. > > > > Example: > > > > CREATE CQ cq_monthly_spread > > RESAMPLE EVERY 1mo RANGE 1mo > > BEGIN > > SELECT max_value(s), min_value(s) > > INTO root.db.device(monthly_max, monthly_min) > > FROM root.db.device > > GROUP BY(1mo) > > END > > > > In the Asia/Shanghai time zone, an execution at 2024-03-01 00:00 should > > cover: > > > > [2024-02-01 00:00, 2024-03-01 00:00) > > > > For compatibility, our current implementation direction is: > > > > - Add optional structured duration fields to TCreateCQReq while > keeping > > the existing i64 fields for legacy readers. > > - Let new ConfigNodes prefer the structured duration fields. > > - Treat old requests and old snapshots without structured fields as > > fixed-duration CQs. > > - Version the CQInfo snapshot format. > > - Preserve the original SQL returned by SHOW CQS. > > - Avoid silently migrating existing flattened mo/y CQs by reparsing > > their saved SQL. Users can recreate those CQs to opt into calendar > > semantics. > > - Allow calendar CQ creation only after all ConfigNodes have been > > upgraded. > > - Keep the DataNode execution RPC based on concrete startTime/endTime > > values. > > > > Before implementation, we would appreciate feedback on the following > > semantic questions: > > > > 1. > > > > When a calendar EVERY omits BOUNDARY, should it automatically align to > > local calendar boundaries? Our proposal is to use 1970-01-01 00:00:00 > in > > the persisted CQ time zone, while explicit BOUNDARY 0 continues to > mean > > the > > Unix epoch instant. > > 2. > > > > Should RANGE use the boundary-anchored duration-vector formula > described > > above, or should offsets be subtracted directly from each > > already-clamped > > execution timestamp? > > 3. > > > > For comparisons such as 1mo versus 30d, should ambiguous > calendar/fixed > > combinations be conservatively rejected? > > 4. > > > > Should existing persisted mo/y CQs retain their legacy fixed-duration > > behavior until users recreate them? > > 5. > > > > Should the SQL grammar support the full aliases month/year in addition > > to mo/y? > > > > We plan to cover explicit and inherited 1mo/1y, Jan-31, Feb-29, all month > > lengths, multiple time zones, DST transitions, ms/us/ns precision, > > BLOCKED/DISCARD catch-up, leader recovery, serialization, and legacy > > snapshots. > > > > Any comments or suggestions on the proposed semantics would be greatly > > appreciated. > > > > Best regards, > > Bryan Yang(杨易达) > > >
