MM/dd/yyyy date ranges are not normalized for system date fields, so suggested modDate queries silently return nothing
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem Statement
MM/dd/yyyy date ranges are not normalized when the date field is a system field, so a query that dotCMS itself suggests returns no results.
The Show Query dialog in Content Search (Content → Search → Search dropdown → Show Query) documents:
+modDate:[12/15/2006 TO 02/03/2010]
Copy that into the Query Tool and it silently returns nothing. The same range against a client-added content-type date field (news.expire:[12/15/2006 TO 02/03/2010]) works correctly. The format is therefore half-supported: valid for custom date fields, broken for system date fields.
This is a parser bug, not a documentation bug. The suggested query text is reasonable and should keep working verbatim — the fix belongs in the query normalization so that MM/dd/yyyy behaves identically regardless of whether the field is a system field (modDate, creationDate, …) or a date field added by the client.
Impact: Anyone who builds a date-filtered content query from the built-in query help — including Support, who hands these queries to customers. The failure is silent: no error, just an empty result set, so it reads as "no matching content" rather than "malformed query". Surfaced while helping a customer build a modDate cutoff query for a content cleanup (FD #38919).
Root cause
In LuceneQueryDateTimeFormatter.findAndReplaceQueryDates():
- The
MM/dd/yyyy→MM/dd/yyyy 00:00:00 TO MM/dd/yyyy 23:59:59padding for a clause starting withmoddate:sits inside thefor (Field field : dateFields)loop.dateFieldsis only populated from clauses shapedcontentTypeVar.fieldVar:— so whenmodDateis the only date clause in the query,dateFieldsis empty and the branch never executes. This is also why the check is a hardcodedclause.startsWith("moddate:")rather than a general system-date-field concept. - The generic fallback passes near the end of the method are field-agnostic, which is the right shape — but their value regexes are too narrow:
\[([0-9]*) (TO) ([0-9]*)\]and\[([a-z0-9]*) (TO) ([a-z0-9]*)\]. Neither matches a value containing/or a space-separated time component. - The final elasticsearch#2980 workaround then rewrites
/→\/, so Elasticsearch receives+moddate:[12\/15\/2006 TO 02\/03\/2010]against a date-mapped field.
The supporting machinery already exists and is not the problem: LUCENE_DATE_TIME_FORMAT_PATTERNS already enumerates every accepted input form (MM/dd/yyyy, MM/dd/yyyy HH:mm:ss, MM/dd/yyyy hh:mm:ssa, yyyyMMdd, yyyyMMddHHmmss, and the time-only variants), and replaceDateTimeFormatInClause() already tries them in order and converts to the ES-accepted format.
Suggested approach: widen the value pattern in the field-agnostic fallback pass (item 2) to cover the non-digit date shapes already listed in LUCENE_DATE_TIME_FORMAT_PATTERNS, and apply the 00:00:00 / 23:59:59 boundary padding there too. Because that pass runs before the slash-escaping step, a normalized value has no slashes left to escape and item 3 resolves itself. That keeps the fix in one field-agnostic place instead of extending the hardcoded moddate: special case into a system-field allowlist — the pattern that produced this gap in the first place. Implementer's call, but a per-field-name list should be avoided.
There is currently no test coverage anywhere for findAndReplaceQueryDates.
Affected files
| File | Detail |
|---|---|
dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/LuceneQueryDateTimeFormatter.java |
the normalization gap — primary fix site |
dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/ESContentFactoryImpl.java:1581,1589 |
callers (translateQuery → findAndReplaceQueryDates) |
dotCMS/src/main/webapp/WEB-INF/messages/Language.properties:2597 |
message.contentlet.hint3 — the suggested example that must work as-is |
dotCMS/src/main/webapp/html/portlet/ext/contentlet/view_contentlets_js_inc.jsp:2811-2814 |
renders hint2/hint3/hint4/hint6 into the Show Query dialog |
No documentation change is required by this ticket. The existing help text is the specification: +modDate:[12/15/2006 TO 02/03/2010] must work exactly as printed. (Optional cosmetic follow-up, explicitly not a blocker: the example's 2006–2010 dates are stale and could be refreshed to something like +modDate:[20270101 TO 20301231], and viewcontentlets.message.datetime.hint at Language.properties:5287 could lead with the yyyyMMddHHmmss form. Neither is needed for this fix to be complete.)
Steps to Reproduce
- Log into dotAdmin and go to Content → Search.
- Set Type to any content type (e.g. File) and pick a Site or Folder.
- Open the Search split-button dropdown and choose Show Query.
- In the dialog, read the Date Ranges help block below Ordered by — it shows
Example 1: +modDate:[12/15/2006 TO 02/03/2010]. - Take the Lucene query offered at the top of the same dialog and append that date range, so
modDateis the only date clause:+contentType:FileAsset +languageId:1 +deleted:false +working:true +variant:default +modDate:[12/15/2006 TO 02/03/2010] - Paste it into Dev Tools → Query Tool and run it.
Expected: the content modified in that window — the same result set as the yyyyMMdd equivalent.
Actual: zero results, no error.
Controls that confirm the diagnosis:
| Query | Result today |
|---|---|
+modDate:[12/15/2006 TO 02/03/2010] |
✗ empty |
+modDate:[20061215 TO 20100203] |
✓ correct results |
+news.expire:[12/15/2006 TO 02/03/2010] (client-added date field) |
✓ correct results |
Acceptance Criteria
- A query whose only date clause is a system date field in
MM/dd/yyyyform returns the same result set as itsyyyyMMddequivalent — verified formodDate,creationDate,versionTs, andwfModDate, plus any other system field indexed as a date (pubdate,expdate,sysPublishDate). - The same holds for a client-added content-type date field (
myType.myDateField:[12/15/2006 TO 02/03/2010]) — both on its own and combined in one query with a system date field clause. - Every input form already listed in
LUCENE_DATE_TIME_FORMAT_PATTERNSis normalized for system date fields, not justMM/dd/yyyy:yyyyMMdd,yyyyMMddHHmmss,MM/dd/yyyy HH:mm:ss,MM/dd/yyyy hh:mm:ssa(and thehh:mm a/hh:mmaspacing variants). - A
MM/dd/yyyyrange with no time component still receives the00:00:00(from) and23:59:59(to) boundary padding, so the range is inclusive of both end dates. - The
/→\/escaping no longer corrupts a date range: after normalization no slashes remain in a date value, and the escaping still applies to non-date parts of the query that need it. - The example printed in the Show Query dialog works verbatim. Pasting
+modDate:[12/15/2006 TO 02/03/2010]into the Query Tool returns results without any change to the help text. - No regression: existing queries using
yyyyMMdd/yyyyMMddHHmmssranges, and existing content-type date-field queries, behave exactly as they do today. The Query Tool's own shipped example (+contentType:fileAsset +deleted:false +modDate:[20250101 TO 20991231]) still works. - Edge cases: open-ended and wildcard ranges (
[20230101 TO *],[* TO 20230101]) continue to work; a malformed or unparseable date value fails loudly or is passed through unchanged rather than silently producing an empty result set. - Unit tests are added for
LuceneQueryDateTimeFormatter.findAndReplaceQueryDates()— currently untested — covering each supported input format, for a system date field alone, a content-type date field alone, and both combined.
dotCMS Version
Reported by a customer on 25.07.10 LTS. The code paths above were inspected on a current main checkout and are unchanged, so this affects main as well as LTS.
Severity
Medium - Some functionality impacted
Links
- Freshdesk ticket #38919
- elasticsearch#2980 — the slash-escaping workaround referenced in the code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in dotCMS/src/main/java/com/dotcms/content/elasticsearch/business/LuceneQueryDateTimeFormatter.java and inspect findAndReplaceQueryDates(), its date patterns, and the callers in ESContentFactoryImpl.java at the referenced lines. Add unit coverage for system and content-type date ranges across the listed formats, including boundary padding and wildcard cases. Done means the Show Query modDate example and existing yyyyMMdd queries normalize without regressions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- elasticsearch, java
- Domain
- backend, search
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100