[ 
https://issues.apache.org/jira/browse/GROOVY-12124?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18094251#comment-18094251
 ] 

ASF GitHub Bot commented on GROOVY-12124:
-----------------------------------------

paulk-asert merged PR #2653:
URL: https://github.com/apache/groovy/pull/2653




> 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)

Reply via email to