* Build the calendar month grid in UTC
The grid walked a cursor at local midnight and stepped it with setDate(getDate() + 1). Chile starts DST at 24:00 on the first Saturday of September, so local midnight of 6 September 2026 does not exist, and Qt's V4 engine resolves a missing local time backward -- onto 5 September 23:00, the same calendar date, which the next iteration reads again. September 2026 draws 30 31 1 2 3 4 5 and then 5 6 7 8 9 10 11, and every later date sits one weekday early. Cuba, Lebanon, the Azores and Egypt change over at 00:00 too and break the same way in their own transition month; where the gap lands on a leading padding cell instead, the whole six-week grid shifts by a day with no duplicate in it.
Node resolves the identical gap forward, so the suite has never seen this: running the shipped monthGrid under Node across all 598 tzdata zones for 2020-2035 reports nothing, while the same code under the QML engine breaks 402 grids. A sequence of civil dates never needed a wall clock, so it walks UTC, where every day is 24 hours long, and the test pins that by building the grid with a Date whose local constructor and accessors throw.
stepMonth reads a month back off the same kind of date. No zone puts a midnight gap on a first of the month, so it is not broken today, but it moves with the grid rather than waiting for a tzdata release to make it a second bug.
Co-Authored-By: Codex XHigh <noreply@openai.com>
* Name the calendar heading's month from local noon
The heading built a local midnight on the first of the month, and that midnight does not always exist: Cuba started DST at 00:00 on 1 April 2012, so in Havana the QML engine resolves it back onto 31 March and the heading reads March 2012 above an April grid. Noon exists on every first of the month there has been, and keeping it local is what makes Qt.formatDate print the right month in every zone.
The Apia case comes from #13186: Samoa skipped 30 December 2011 entirely, so unlike a one-hour midnight gap, Node's V8 cannot resolve its way past it, and the test fails on the old grid under Node instead of only in the shell.
Co-Authored-By: Codex Medium <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Codex XHigh <noreply@openai.com>
Co-authored-by: Omarchybot <317366263+omarchybot@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add a clock format with live seconds
Right-clicking the clock now reaches "Thursday 09:39:23" and its AM/PM twin, and the widget's SystemClock ticks once a second only while a format that prints seconds is showing — every other format keeps the minute precision it had, so nobody pays for a repaint a second to read a label that changes once a minute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Read an unterminated literal in a clock format as text
Qt reads an opening quote with no closing one as a literal running to the end of the format, so "HH:mm 'sec" prints "09:39 sec" and never a second count — but the seconds test stripped only balanced quotes, saw the s, and put the widget on a per-second tick for a label that changes once a minute. The wiring assertions went the other way: each passed while the feature was broken, so hard-coding showsSeconds to false, dropping the label's onDateChanged, or commenting the precision line out and leaving the text behind all shipped green. Comments now come out of the source before it is matched, and both halves of the tick are asserted.
Co-Authored-By: Codex XHigh <noreply@openai.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Every preset in the right-click ring was 24-hour, so a 12-hour label was
something you had to hand-write into shell.json. Pair each locale-shaped
time preset with its AM/PM twin, and give vertical bars one stacked
variant. The ISO preset keeps its 24-hour clock, since ISO 8601 writes
time that way.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Double-tapping the year bar asks for a birth year and a life expectancy,
and a second bar appears below measuring one against the other. Tab moves
between the two, Enter commits the pair, Escape drops them. Hovering the
bar names the thing, and double-tapping it puts it away again.
A birth year rather than an age, so the bar keeps counting on its own
instead of going stale the moment it is entered. Expectancy defaults to
ninety and falls back to it when what is entered makes no sense, so the
bar always has something to measure against; a birth year that makes no
sense leaves the bar hidden instead, which is also where it starts.
Putting the bar away keeps the expectancy, so setting a birth year again
brings your own number back rather than the default.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clicking the clock reveals a month grid with ISO week numbers, a year
progress meter, and month stepping. Right click walks the common label
formats and writes the chosen one back to shell.json, so the bar shows
what the config stores. The week start toggles from the grid's "W"
heading and persists as weekStartDay, defaulting to the locale's own
first day.
Rich popup widgets live in their own plugin directories, so the clock
moves out of bar/widgets/ into panels/clock/. The id is unchanged, so
existing layouts and centerAnchor keep working.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>