Skip to content

fix(android): keep hour when changing minutes in spinner with minuteInterval 20 or 30 - #1066

Open
huytdps13400 wants to merge 1 commit into
react-native-datetimepicker:masterfrom
huytdps13400:fix/android-minute-interval-spinner-hour
Open

huytdps13400 wants to merge 1 commit into
react-native-datetimepicker:masterfrom
huytdps13400:fix/android-minute-interval-spinner-hour

Conversation

@huytdps13400

Copy link
Copy Markdown

Summary

Fixes #1033
Fixes #822

On Android, with display="spinner" and minuteInterval={30} (or 20), changing the minutes also changes the hour: picking :30 from 8:00 gives 7:30, and picking :00 from 8:30 gives 9:00.

Root cause: the platform TimePickerSpinnerDelegate moves the hour by one whenever the minute spinner goes from its max value to its min value (or the other way), because it assumes the wheel wrapped around. With minuteInterval 30 the minute spinner only has 2 values (00, 30), and with 20 it has 3. NumberPicker does not allow wrapping with fewer than 3 steps between min and max, so these changes are never real wrap-arounds. With interval 30, every minute change shifted the hour.

Change: in MinuteIntervalSnappableTimePickerDialog, in spinner mode, when the minute spinner cannot wrap (NumberPicker#getWrapSelectorWheel() is false) and a single onTimeChanged changes both the minute and the hour, the hour is restored to its previous value. Intervals whose minute spinner can wrap (1–15) are unchanged, so a real wrap such as 8:45 → 9:00 still works. Clock mode is unchanged.

Test Plan

I verified this with a local Robolectric test, which I did not include because the repo has no Android unit test setup. I can add it if you want. The test opens RNDismissableTimePickerDialog with R.style.SpinnerTimePickerDialog, changes the minute NumberPicker the way a user scroll does (setValueInternal(index, true)), presses the positive button and checks the hour and minute reported to OnTimeSetListener. It ran on SDK 26, 28, 30, 33, 34 and 35.

Case Before After
interval 30, 08:00 → pick 30 07:30 08:30
interval 30, 08:30 → pick 00 09:00 08:00
interval 30, 12h, 11:30 AM → pick 00 12:00 PM 11:00 AM
interval 30, 23:00 → 30 → 00 → 30 22:30 23:30
interval 30, change hour to 9, then pick 30 08:30 09:30
interval 30, updateTime(10, …) then pick 00 wrong hour 10:00
interval 20, 08:00 → 40 (typed) 07:40 08:40
interval 15, 08:45 → 00 (real wrap) 09:00 09:00
interval 1, 08:59 → 00 (real wrap) 09:00 09:00

I also compiled the library with :react-native-community_datetimepicker:testDebugUnitTest (old arch). yarn test and yarn lint don't cover this change because it is Java only.

What's required for testing (prerequisites)?

An Android device or emulator.

What are the steps to reproduce (after prerequisites)?

Open the example app with mode="time", display="spinner" and minuteInterval={30}, then scroll the minutes between 00 and 30. The hour should stay the same.

Compatibility

OS Implemented
iOS ❌
Android ✅

Checklist

  • I have tested this on a device and a simulator (verified with Robolectric only, see above)
  • I added the documentation in README.md (not needed)
  • I updated the typed files (TS and Flow) (no API change)
  • I added a sample use of the API in the example project (example/App.js) (not needed)
  • I have added automated tests, either in JS or e2e tests, as applicable (local Robolectric test, see above)

This fix was prepared with AI assistance (Claude Code) and verified locally with the tests above.

🤖 Generated with Claude Code

…nterval 20 or 30

The platform TimePicker spinner moves the hour by one whenever the minute
spinner goes from its max to its min value (or back), assuming the wheel
wrapped around. With minuteInterval 20 or 30 the minute spinner has too few
values to wrap, so every such change shifted the hour. Restore the hour in
that case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant