Read day of month, month and year as prose - #718
Open
austek wants to merge 4 commits into
Open
Conversation
"0 59 10 ? 1/2 MON#1 *" read "at 10:59 every 2 months from month 1 Monday 1 of every month". The nth day of week printed its position as a bare number, and claimed "of every month" right after the month field had restricted it to every second month. Give the # and L forms their own phrasing, so they read "on the first Monday of the month" and "on the last Friday of the month" and no longer contradict a restricted month. Positions past the fifth, outside the Quartz range but reachable through the generic descriptor, fall back to the plain number. Field order is untouched, so the day of week still follows the month rather than leading the sentence as the report suggests. Fixes jmrozanec#126
Minute 0 was always suppressed as an implied default, so an expression firing on a sub-minute schedule lost the minute bounding it. "* 0 9-23 * * ?" described as "every second every hour between 9 and 23", roughly sixty times the firings it actually produces. Only suppress minute 0 when the seconds are implicit too. Also fixes "5 0 9-23 * * ?", "0/5 0 * * * ?" and "* 0 */4 * * ?", and covers the deliberate suppression cases so they stay collapsed. Makes the strategy set insertion ordered and hoists the duplicated predicate call while here. Refs jmrozanec#3
"0 0 0 1 1 ?" described as "at 00:00 at 1 day at January month" and
"0 15 10 * * ? 2005" as "at 10:15 at 2005 year". Give day of month, month
and year their own phrasing so they read "on day 1 in January" and "in 2005".
Drop the start of an every expression when the period is 1 and the start is
0, since "every 1 unit from 0" is just "every unit", so "0/1 * * * * ?" is
now "every second" rather than "every second from second 0". A meaningful
start is kept: "5/1 * * * * ?" still reads "every second from second 5".
Omit the unit word where the value already names it, so months, years and
days of week read "from October" rather than "from month 10". Months no
longer fall back to the raw number inside an every expression, which is what
produced "month 10".
Months and years take separate bundle keys even though English formats both
as "in {0}", so a translator can decline them differently. The keys are only
in the base bundle for now, so other locales fall back to English for these
phrases.
Refs jmrozanec#3
Day of week kept the generic template, so "0 10,44 14 ? 3 WED" read "... in March at Wednesday day" once months had been fixed. Give it the same treatment, so it reads "in March on Wednesday". Fixing the single value exposed the list form, which still read "at Monday, Wednesday and Friday days". Match lists to the single value they generalise across day of month, day of week, month and year, so a list and a single value do not use two different vocabularies in one sentence. A list reuses the key of its single value form, passing the joined values as the argument, so only day of month needs a plural key of its own. Ranges, every expressions and the L and # forms are untouched. Refs jmrozanec#3
austek
force-pushed
the
fix/issue_3_phrasing
branch
from
July 28, 2026 14:41
0077ebe to
2093161
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of your changes
Follows #717 and #719, and is stacked on both — this branch contains those commits too, so please merge #719 and #717 first and this will reduce to its own two commits. Together the three cover the concrete cases reported on #3.
Three reported descriptions, all still reproducing on master:
0 0 0 1 1 ?0/1 * * * * ?3/4 5/6 7/8 9/2 10/2 ? 2017/2Three changes in
descriptor/produce that:Onphrasing instead of the generic "at <value> <unit>" template.describe(Every)drops the start clause when the period is 1 and the start is 0, since "every 1 unit from 0" is just "every unit". A meaningful start is kept —5/1 * * * * ?still reads "every second from second 5", and0 0/5 14 * * ?still reads "every 5 minutes from minute 0 at 14 hour".monthsInstancealso no longer substitutesObject::toStringwhen the expression is anEvery, which is what produced "month 10" in the first place.Day of week and the list forms follow, so the whole vocabulary agrees rather than only the three reported expressions:
A list reuses the bundle key of its single value form, passing the joined values as the argument, so a translator fixes one string rather than two. Only day of month needs a plural key of its own. Ranges and
Everyexpressions are untouched —MON-FRIstill reads "every day between Monday and Friday". TheLand#day of week forms are untouched by this PR; they read "on the last Friday of the month" and "on the first Monday of the month" because #719 sits below it in the stack.Impact Analysis
Output changes for expressions with an explicit day of month, day of week, month or year, whether single or a list, and for
x/1starting at 0. Callers asserting on those exact strings will need updating.I diffed 50 Quartz and Unix expressions between this branch and the commit it stacks on: 21 lines change, all of them the cases above, nothing incidental. Seven pre-existing expectations in this repo are updated across the two commits here — three in
CronDescriptorQuartzIntegrationTest, two rows ofIssue126Test(the month clause of the #719 expression moves from "from month 1" to "from January"), one inCronDescriptorTestand one inExecutionTimeQuartzIntegrationTest.Two things reviewers should weigh:
0 10,44 14 ? 3 WEDreading "… in March at Wednesday day", and fixing that in turn exposed lists still reading "at Monday, Wednesday and Friday days". Both are now consistent with the single value forms; see the table above. Hours and minutes keep their existingat 1, 2, 3 and 4 hours, since numeric units read fine as a list and are not part of Descriptions could be better #3.rohas noattoday). Months and years take separate keys,in_month_xandin_year_x, even though English formats both asin {0}, precisely so a translator can decline them differently rather than being forced into one template. Translations need native speakers and I did not want to guess them.One rough edge left in place: an expression restricting both day of month and day of week repeats the preposition, so
30 4 1,15 * 5reads "at 04:30 on days 1 and 15 on Friday". That is the field concatenation inCronDescriptor.describe, not the phrasing changed here, and it was equally repetitive before ("at 1 and 15 days at Friday day"). Joining the fields properly means deciding an order for the whole sentence, which is the larger change #126 also asks for.I am aware of the 2018 discussion where the template approach was set aside in favour of neural translation. This is not an attempt to reopen that — it is the minimum needed to make the specific expressions in #3 grammatical, and it leaves the per-language phrasing decisions to the bundles. Happy to close it if you would rather keep that direction clear.
TestDescriptoris left disabled; its expectations describe a different output shape (comma separated clauses, ordinals, am/pm) and reaching them is a larger change than this.Checklist