[
https://issues.apache.org/jira/browse/GROOVY-12124?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18093147#comment-18093147
]
ASF GitHub Bot commented on GROOVY-12124:
-----------------------------------------
testlens-app[bot] commented on PR #2653:
URL: https://github.com/apache/groovy/pull/2653#issuecomment-4862789824
## ✅ All tests passed ✅
🏷️ Commit: 68b3cba78197e2b56e1947771f2470924fc0e1b3
▶️ Tests: 102771 executed
⚪️ Checks: 31/31 completed
---
_Learn more about TestLens at [testlens.app](https://testlens.app)._
> Modernize the TimeCategory date/time DSL: add a java.time flavor and a
> dequirked java.util.Date flavor
> ------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12124
> URL: https://issues.apache.org/jira/browse/GROOVY-12124
> Project: Groovy
> Issue Type: Improvement
> Reporter: Paul King
> Priority: Major
>
> h1. Modernize the TimeCategory date/time DSL
> h2. Summary
> Introduce a {{java.time}}-based parallel to the legacy
> {{groovy.time.TimeCategory}}
> DSL, and give the existing {{java.util.Date}}-based DSL a cleaned-up
> ("dequirked")
> home in the module that already owns Date support. Net result: one familiar
> DSL
> ({{1.hour.ago}}, {{date + 3.months}}, {{2.days.from.now}}) available in two
> flavors —
> modern {{java.time}} output or classic {{java.util.Date}} output — both
> quirk-free.
> h2. Background
> {{groovy.time.TimeCategory}} (a {{use()}} category in *groovy core*) layers
> duration
> arithmetic onto {{java.util.Date}}/{{Calendar}}: {{Integer}} producers
> ({{1.hour}},
> {{2.months}}), operators ({{date + duration}}, {{date - date}}), and
> relative-time
> properties ({{.ago}}, {{.from.now}}). It is backed by the
> {{groovy.time.Duration}}
> hierarchy (Duration / TimeDuration / DatumDependentDuration /
> TimeDatumDependentDuration).
> Two problems motivate this work:
> * *No java.time equivalent.* Modern code uses {{java.time}}, but there is no
> {{1.hour}}/{{2.months}} producer for it. The {{groovy-datetime}} module
> already
> provides all the arithmetic (plus/minus/next/multiply/between/upto…) on
> {{java.time}}
> types — the only gap is the number→amount producers and
> {{.ago}}/{{.from.now}}.
> * *The Date DSL is split and quirky.* All other {{java.util.Date}} DSL methods
> ({{date + int}}, {{date.next()}}, {{date[YEAR]}}, {{clearTime}}, {{format}},
> {{date - date -> int}}) live in the optional *groovy-dateutil* module, while
> TimeCategory lives in core — so half of Date arithmetic is core, half is
> optional,
> and {{date - date}} even resolves differently between them.
> h2. Proposal
> Add two categories and deprecate the legacy one:
> || Class || Module || Output type || Status ||
> | {{org.apache.groovy.datetime.TimeCategory}} | groovy-datetime |
> {{java.time}} (Duration/Period, LocalDate/LocalDateTime) | new |
> | {{org.apache.groovy.dateutil.TimeCategory}} | groovy-dateutil |
> {{java.util.Date}} | new (dequirked) |
> | {{groovy.time.TimeCategory}} (+ Duration hierarchy) | core |
> {{java.util.Date}} | deprecated, frozen |
> The two new categories share one DSL surface and one semantics spec; only the
> terminal
> return types differ. The legacy class stays byte-for-byte behavior-compatible
> (frozen),
> so existing users are unaffected until they choose to migrate.
> h3. Producer mapping (both flavors)
> * {{seconds, minutes, hours, millis, nanos}} → {{java.time.Duration}}
> (datetime) /
> {{TimeDuration}} (dateutil)
> * {{days, weeks, months, years}} → {{java.time.Period}} (datetime) /
> {{Duration}}/{{DatumDependentDuration}} (dateutil)
> * {{.ago}} / {{.from.now}} → {{LocalDate}}/{{LocalDateTime}} (datetime) /
> {{java.util.Date}} (dateutil)
> Note: {{java.time}} deliberately keeps date-based ({{Period}}) and time-based
> ({{Duration}}) amounts separate, so {{date + 2.months + 3.hours}} works by
> left-associative chaining rather than a combined amount type.
> h2. Design decisions
> * *(proposed, pending team review)* The dateutil flavor uses its *own*
> dequirked value
> classes (option "B1"), not {{java.time}} internally (option "B2").
> Rationale: B1 keeps
> the DSL return shape ({{.seconds}}/{{.days}} component accessors, bespoke
> {{toString}},
> the type lattice), so existing tests and user code port ~1:1; it is fully
> self-contained
> within groovy-dateutil (no dependency on groovy-datetime being on the
> classpath — matching
> today, where the Duration classes rely on no external extension methods).
> B2 would change
> component-accessor and {{toString}} semantics and require either
> duplicating datetime's
> operator DGM or a new dateutil→datetime module dependency.
> * *(proposed, pending team review)* Deprecate {{groovy.time.TimeCategory}}
> with a removal
> trajectory (future major). The dateutil copy gives Date users a
> non-deprecated home, so
> the deprecation is not coercive toward java.time.
> * Keep the legacy {{groovy.time.Duration}} value classes exactly as-is (do
> not move; the
> dequirked classes are new copies in {{org.apache.groovy.dateutil}} — no
> split package).
> * The legacy class is *not* a forwarder to the new one (behavior differs); it
> stays intact.
> h2. Quirks removed in the new flavors
> || # || Legacy behavior || New behavior ||
> | A | {{.ago}}/{{.from.now}} floor to midnight for day/month/year durations
> but keep time for hours/min/sec (inconsistent) | Time-of-day preserved
> uniformly (datetime: {{Period}}→{{LocalDate}},
> {{Duration}}→{{LocalDateTime}}) |
> | B | {{DatumDependentDuration.toMilliseconds()}} resolves against {{new
> Date()}} — nondeterministic | Deterministic: uses {{ChronoUnit}} estimates
> ({{1.year == 12.months}} still holds exactly); {{java.time}} {{Period}}
> simply has no {{toMillis}} |
> | C | Four-class Duration lattice incl. {{TimeDatumDependentDuration}} |
> Retained in dateutil (B1); not needed in datetime (chaining) |
> | D | {{Duration}} = 24h/day for {{toMillis}} but DST-aware when added |
> Documented/consistent |
> | E | {{getTimeZone}} (already {{@Deprecated}}), {{getDaylightSavingsOffset}}
> | Dropped from new flavors (superseded by zone-aware java.time) |
> Side effect of A+B: {{getAgo}}/{{getFrom}}/{{toMilliseconds}} collapse to
> single
> implementations on {{BaseDuration}}, removing the per-subclass overrides
> (~40% less
> duplication in the value classes).
> h2. Prototype validation
> A working B1 prototype of the dateutil flavor (six classes) was built and
> exercised
> against a port of {{TimeCategoryTest}}:
> * All arithmetic/{{toString}}/comparison assertions ported with *only* the
> {{use()}}/import
> target changed — no assertion edits.
> * Three added assertions demonstrate the dequirks; the same probes run
> against the legacy
> class confirm the delta (legacy {{3.days.ago}} → {{00:00:00}};
> {{1.month.ago}} off by the
> millis-since-midnight; {{5.months.toMilliseconds()}} varies with the
> current date).
> * Only the value-class suites ({{DurationTest}},
> {{DatumDependentDurationTest}}) need edits,
> confined to the ~6 methods that assert the midnight-flooring /
> {{now}}-relative behavior.
> h2. Scope / tasks
> * [ ] {{org.apache.groovy.datetime.TimeCategory}} + tests + spec section
> (_working-with-datetime-types_)
> * [ ] {{org.apache.groovy.dateutil.TimeCategory}} (B1, dequirked) + value
> classes + tests + spec section
> * [ ] Deprecate {{groovy.time.TimeCategory}} (Javadoc {{@deprecated}}
> pointing to both replacements)
> * [ ] Reconcile/document the {{date - date}} collision (int days vs Duration)
> within groovy-dateutil
> * [ ] Add {{Long}}/{{nanos}} support (enhancement over the Integer-only
> legacy)
> * [ ] Changelog + docgenerator entries
> h2. Open questions (pending team review)
> * B1 vs B2 for the dateutil flavor (recommendation: B1).
> * Commit to eventual removal of {{groovy.time.TimeCategory}} (hard
> {{@Deprecated}}), or
> soft-deprecate in docs only?
> * Category name: reuse the simple name {{TimeCategory}} in both new packages
> (symmetry, but
> dual-import hazard) vs a distinct name for the datetime flavor.
> * Global DGM producers (static-compilation friendly) in addition to the
> {{use()}} category —
> now, later, or never?
--
This message was sent by Atlassian Jira
(v8.20.10#820010)