Skip to content

Fix #1515: Calendar.setDate/setSelectedDate/setCurrentDate preserve hour/minute/second/millis#5117

Merged
shai-almog merged 1 commit into
masterfrom
fix-1515-calendar-date-preservation
May 30, 2026
Merged

Fix #1515: Calendar.setDate/setSelectedDate/setCurrentDate preserve hour/minute/second/millis#5117
shai-almog merged 1 commit into
masterfrom
fix-1515-calendar-date-preservation

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Closes #1515. The 2015 reporter found that the UI Calendar component was silently normalising the time-of-day on every setDate / setSelectedDate / setCurrentDate call — MonthView.setSelectedDay and setCurrentDay forcibly reset HOUR_OF_DAY=1, MINUTE=0, SECOND=0, MILLISECOND=0 — so any caller round-tripping a Date through Calendar lost the time component (and depending on the timezone, sometimes the day too).

The constraint

The normalisation is load-bearing for the day-cell renderer: the dates[] array stores normalised millis and the highlight code does exact long equality against SELECTED_DAY/currentDay (lines 1122 and 1302). Simply storing the caller's raw millis silently breaks day highlighting.

The fix

Add two side fields originalSelectedDay and originalCurrentDay that remember the millis the public setter received, separate from the normalised SELECTED_DAY / currentDay used for cell comparison.

  • getDate() and getCurrentDate() return the cached original when one was supplied, falling back to the normalised value otherwise.
  • setDate / setSelectedDate / setCurrentDate populate it.
  • A user-initiated day-cell tap clears both fields (because a tap only conveys day, not time-of-day) so the round-trip cleanly falls back to the cell millis after manual selection.

Test plan

  • New regression test CalendarDatePreservationTest with five cases:
    1. setDate round-trips 13:45:30.500.
    2. setSelectedDate round-trips 23:59:59.999.
    3. setCurrentDate round-trips 09:30:15.250.
    4. Midnight is preserved (pre-fix this became 01:00 and could roll the day backwards in some timezones).
    5. year/month/day-of-month of the round-tripped date still match the input.
  • Before the fix, all five fail (e.g. expected: <1773582330500> but was: <1773529200000>, where the only difference is the time-of-day clobber).
  • After the fix, all five pass.
  • No regressions — the existing CalendarTest and the broader 38-test *Calendar*,*Date* sweep stay green.
  • ASCII-only sources verified.
  • CI verification.

🤖 Generated with Claude Code

The 2015 reporter showed that the UI Calendar component was
silently normalising the time-of-day on every setDate / setCurrentDate
/ setSelectedDate call. MonthView.setSelectedDay and setCurrentDay
forcibly reset HOUR_OF_DAY=1, MINUTE/SECOND/MILLISECOND=0 (lines
1184-1188 and 1055-1070 pre-fix) so any caller round-tripping a Date
through Calendar lost the time component.

The normalisation is load-bearing for the day-cell renderer: the
dates[] array stores normalised millis and the highlight code does
exact long equality against SELECTED_DAY/currentDay (lines 1122 and
1302), so simply storing the raw millis breaks day highlighting.

Add side fields originalSelectedDay / originalCurrentDay that
remember the millis the public setter received, separate from the
normalised SELECTED_DAY / currentDay used for cell comparison. The
public getDate() / getCurrentDate() return the original when one was
supplied; setDate/setSelectedDate/setCurrentDate populate it; a
user-initiated day-cell tap clears it (because a tap only conveys
day, not time-of-day) so we cleanly fall back to the cell millis.

Closes #1515.

Adds maven/core-unittests/.../CalendarDatePreservationTest.java with
five regression cases covering setDate, setSelectedDate, setCurrentDate,
midnight (which pre-fix became 01:00 and could roll the day backwards),
and day-of-month integrity after the round-trip. Existing
CalendarTest stays green; 38 Calendar+date tests overall pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.

Native Android coverage

  • 📊 Line coverage: 12.80% (7454/58229 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.41% (37313/358503), branch 4.30% (1457/33874), complexity 5.40% (1759/32544), method 9.47% (1444/15249), class 15.57% (331/2126)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.80% (7454/58229 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.41% (37313/358503), branch 4.30% (1457/33874), complexity 5.40% (1759/32544), method 9.47% (1444/15249), class 15.57% (331/2126)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1120.000 ms
Base64 CN1 encode 202.000 ms
Base64 encode ratio (CN1/native) 0.180x (82.0% faster)
Base64 native decode 1352.000 ms
Base64 CN1 decode 280.000 ms
Base64 decode ratio (CN1/native) 0.207x (79.3% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 364 seconds

Build and Run Timing

Metric Duration
Simulator Boot 67000 ms
Simulator Boot (Run) 1000 ms
App Install 28000 ms
App Launch 17000 ms
Test Execution 361000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 730.000 ms
Base64 CN1 encode 2241.000 ms
Base64 encode ratio (CN1/native) 3.070x (207.0% slower)
Base64 native decode 619.000 ms
Base64 CN1 decode 1167.000 ms
Base64 decode ratio (CN1/native) 1.885x (88.5% slower)
Base64 SIMD encode 447.000 ms
Base64 encode ratio (SIMD/native) 0.612x (38.8% faster)
Base64 encode ratio (SIMD/CN1) 0.199x (80.1% faster)
Base64 SIMD decode 611.000 ms
Base64 decode ratio (SIMD/native) 0.987x (1.3% faster)
Base64 decode ratio (SIMD/CN1) 0.524x (47.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 60.000 ms
Image createMask (SIMD on) 21.000 ms
Image createMask ratio (SIMD on/off) 0.350x (65.0% faster)
Image applyMask (SIMD off) 379.000 ms
Image applyMask (SIMD on) 76.000 ms
Image applyMask ratio (SIMD on/off) 0.201x (79.9% faster)
Image modifyAlpha (SIMD off) 152.000 ms
Image modifyAlpha (SIMD on) 72.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.474x (52.6% faster)
Image modifyAlpha removeColor (SIMD off) 195.000 ms
Image modifyAlpha removeColor (SIMD on) 94.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.482x (51.8% faster)
Image PNG encode (SIMD off) 1493.000 ms
Image PNG encode (SIMD on) 1040.000 ms
Image PNG encode ratio (SIMD on/off) 0.697x (30.3% faster)
Image JPEG encode 653.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 30, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 125 seconds

Build and Run Timing

Metric Duration
Simulator Boot 61000 ms
Simulator Boot (Run) 0 ms
App Install 14000 ms
App Launch 8000 ms
Test Execution 322000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 669.000 ms
Base64 CN1 encode 1563.000 ms
Base64 encode ratio (CN1/native) 2.336x (133.6% slower)
Base64 native decode 483.000 ms
Base64 CN1 decode 1081.000 ms
Base64 decode ratio (CN1/native) 2.238x (123.8% slower)
Base64 SIMD encode 378.000 ms
Base64 encode ratio (SIMD/native) 0.565x (43.5% faster)
Base64 encode ratio (SIMD/CN1) 0.242x (75.8% faster)
Base64 SIMD decode 460.000 ms
Base64 decode ratio (SIMD/native) 0.952x (4.8% faster)
Base64 decode ratio (SIMD/CN1) 0.426x (57.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 71.000 ms
Image createMask (SIMD on) 16.000 ms
Image createMask ratio (SIMD on/off) 0.225x (77.5% faster)
Image applyMask (SIMD off) 155.000 ms
Image applyMask (SIMD on) 53.000 ms
Image applyMask ratio (SIMD on/off) 0.342x (65.8% faster)
Image modifyAlpha (SIMD off) 117.000 ms
Image modifyAlpha (SIMD on) 56.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.479x (52.1% faster)
Image modifyAlpha removeColor (SIMD off) 134.000 ms
Image modifyAlpha removeColor (SIMD on) 125.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.933x (6.7% faster)
Image PNG encode (SIMD off) 1090.000 ms
Image PNG encode (SIMD on) 911.000 ms
Image PNG encode ratio (SIMD on/off) 0.836x (16.4% faster)
Image JPEG encode 464.000 ms

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog shai-almog merged commit 9618c78 into master May 30, 2026
22 of 23 checks passed
@shai-almog shai-almog deleted the fix-1515-calendar-date-preservation branch May 30, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Calendar Component doesn't respect passed in Date object in setDate(), setCurrentDate(), setSelectedDate() methods

1 participant