Index Maintenance "Created" column shows date +1 day for indexes built in the evening (date rendered in UTC, time in configured TZ)
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Problem Statement
On the ES Index Maintenance screen (System → Maintenance → Index), the Created column shows a date that is one day ahead for any index whose name-timestamp falls in the evening (local time). The date portion is rendered in the server's JVM default timezone (UTC on cloud pods) while the time portion is rendered in the configured System/Company timezone. For an index created after ~8 PM in a US timezone — already past midnight UTC — the date rolls forward by one while the time still displays correctly.
This is display-only. The alias name, the underlying index, content, and search are unaffected.
Root cause analysis
The Created cell is built in index_stats.jsp (lines 114-117) as:
d = dater.parse(x.split("_")[1]); // parse name suffix in JVM default TZ
myDate = UtilMethods.dateToPrettyHTMLDate(d) + " " + UtilMethods.dateToHTMLTime(d);
// ^ DATE — see below ^ TIME — sets configured TZ
The two halves resolve to different timezones:
Time — UtilMethods.dateToHTMLTime() (UtilMethods.java:706-712) calls DATE_TO_HTML_TIME.setTimeZone(APILocator.systemTimeZone()) on every invocation → configured ET. Correct.
Date — UtilMethods.dateToPrettyHTMLDate() (UtilMethods.java:748-753) formats via the static DATE_TO_PRETTY_HTML_DATE (UtilMethods.java:132) and never calls setTimeZone:
public static final String dateToPrettyHTMLDate(java.util.Date x) {
if (x == null) return "";
return DATE_TO_PRETTY_HTML_DATE.format(x); // no setTimeZone → JVM default captured at class-load
}
A static SimpleDateFormat captures TimeZone.getDefault() once, at class initialization. UtilMethods is loaded very early in boot (container default = UTC), before dotCMS applies the configured Company timezone via TimeZone.setDefault(...) (CompanyManagerUtil.java:207, StartupLogger.java:23). So the static date formatter stays pinned to UTC for the life of the JVM, while everything constructed after the flip (the index name via LocalDateTime.now(), the per-request parser, and dateToHTMLTime) uses ET.
Net: date drawn in UTC, time drawn in ET → evening-built indexes cross midnight in UTC and display the next day.
Impact
Cosmetic / display-only — no functional impact. dateToPrettyHTMLDate is used only in display surfaces (the two index_stats JSPs and DotCMSMacroWebAPI). The alias name is correct and authoritative. The functional age calculation (IndiciesInfo.java:143-145) uses a separate formatter that parses in the same live timezone it was written in, so it round-trips correctly and index age/selection is unaffected; ES routing keys off alias names, not parsed dates. Content, publish/expire dates, and search are unaffected.
Note: the same static-formatter timezone gap also affects any template using $UtilMethods.dateToPrettyHTMLDate(...) via the Velocity macro — evening dates would render in UTC there too. Worth confirming scope.
Proposed fix
Set the timezone on each call, matching the sibling dateToHTMLTime:
public static final String dateToPrettyHTMLDate(java.util.Date x) {
if (x == null) return "";
DATE_TO_PRETTY_HTML_DATE.setTimeZone(APILocator.systemTimeZone());
return DATE_TO_PRETTY_HTML_DATE.format(x);
}
Longer term: DATE_TO_PRETTY_HTML_DATE (and the other shared mutable static SimpleDateFormats in UtilMethods) are not thread-safe and should be replaced with a ThreadLocal or DateTimeFormatter. Recommend also auditing sibling methods (e.g. dateToPrettyHTMLDate2 / DATE_TO_PRETTY_HTML_DATE_2) for the same missing setTimeZone.
Steps to Reproduce
- Set the Company/System timezone to a zone behind UTC (e.g. America/New_York) on a pod whose JVM default is UTC.
- Trigger a reindex (or create any index) at a local wall-clock time after roughly 8 PM — i.e. a moment that is already the next calendar day in UTC.
- Open System → Maintenance → Index.
- Look at the Created column for that index.
Expected
Created shows the same calendar day as the index name timestamp and the local reindex time — e.g. name …20260826202116 → "Wed, August 26 2026 8:21PM".
Actual
The date is one day ahead while the time is correct — e.g. name …20260826202116 → "Thu, August 27 2026 8:21PM".
Acceptance Criteria
- On the Index Maintenance screen, the Created date and time are both rendered in the configured System/Company timezone, so an index built at any hour shows the same calendar day as its name timestamp and local creation time.
- Midday/morning indexes continue to display correctly (no regression).
- dateToPrettyHTMLDate honors APILocator.systemTimeZone() (or the appropriate user/system TZ) regardless of JVM default and class-load order.
- No functional regression: index age (IndiciesInfo), index selection, reindex switch, and ES routing behave as before.
- $UtilMethods.dateToPrettyHTMLDate(...) in Velocity renders evening dates on the correct calendar day.
- (If addressed) shared static SimpleDateFormat usage in UtilMethods is made thread-safe.
- Regression test covering an evening (post-midnight-UTC) timestamp with a behind-UTC company timezone asserting date + time agree.
dotCMS Version
26.08.03-01
Severity
Medium - Some functionality impacted
Links
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 with the Created-column formatting in index_stats.jsp and the date helpers in UtilMethods.java, then review IndiciesInfo.java to confirm age behavior remains unchanged. Add a regression test for an evening timestamp in a behind-UTC company timezone, and verify the Index Maintenance screen and $UtilMethods.dateToPrettyHTMLDate(...) show matching local dates without changing index selection or routing behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100