mmazzarolo / react-native-modal-datetime-picker

A React-Native datetime-picker for Android and iOS
MIT License
2.97k stars 397 forks source link

iOS TimePicker - default date actually return the launch date #578

Open ancyrweb opened 3 years ago

ancyrweb commented 3 years ago

Environment

System: OS: macOS 11.1 CPU: (20) x64 Intel(R) Core(TM) i9-10910 CPU @ 3.60GHz Memory: 1.48 GB / 32.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 12.19.0 - ~/.volta/tools/image/node/12.19.0/bin/node Yarn: 1.22.5 - ~/.volta/tools/image/yarn/1.22.5/bin/yarn npm: 6.14.8 - ~/.volta/tools/image/node/12.19.0/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.10.1 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4 Android SDK: Not Found IDEs: Android Studio: 4.2 AI-202.7660.26.42.7351085 Xcode: 12.5/12E262 - /usr/bin/xcodebuild Languages: Java: 14.0.2 - /usr/bin/javac Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: Not Found react-native: Not Found react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

Platforms

iOS

Versions

10.0.0

Description

When using the time picker using an interval (for example 30 minutes), whenever the user clicks "OK" without changing the date, it return the locally cached time. For a DatePicker it's usually not a problem (unless the user starts the app at 11.45 PM and launches the picker at 0.10 AM the next day for example, but it's a edge case) but for the TimePicker it is because it doesn't return the correct hour.

One solution would be to generate a new date whenever the modal opens up. In the case of the time picker on iOS, we'd need to draw an algorithm that generate the closest date using the current time and the interval as a constraint. It seems this bug is deep inside the iOS picker itself.

Reproducible Demo

Something as simple as this should do.

<DateTimePicker
        isVisible={visible}
        onConfirm={confirm}
        onCancel={close}
        mode={"time"}
        date={(variant === "start" ? props.start : props.end) || undefined}
        minuteInterval={30}
        locale={"fr_FR"}
        confirmTextIOS={"Confirm"}
        cancelTextIOS={"Cancel"}
        headerTextIOS={"Choose an hour"}
        minimumDate={variant === "end" && props.start ? props.start : undefined}
        maximumDate={variant === "start" && props.end ? props.end : undefined}
      />
mmazzarolo commented 3 years ago

Hey @rewieer ! :D

Can't test it now, but I'm wondering...

but for the TimePicker it is because it doesn't return the correct hour.

Does the returned value not match what is shown in the UI?

ancyrweb commented 3 years ago

Hey :D That is the problem, the date returned is the one that is generated when the component is mounted. Looks like on iOS, clicking "OK" without selecting anything (using the default) return whatever was left before. But if I change from, for example, 2:30 to 3:00, confirm, then go back to 2:30, there it works. Will investigate more and eventually submit a PR :)

vini-zapid commented 3 years ago

I'm getting the same issue.

ArpitFuturism commented 3 years ago

I am having the same issue but resolved by the below code

<DateTimePickerModal isVisible={isDatePickerVisible} mode={containsTime ? "datetime" : "date"} minimumDate={new Date().setMinutes( new Date().getMinutes() + 5 )} date={new Date().setMinutes(new Date().getMinutes() + 5)} display="spinner" onConfirm={handleConfirm} onCancel={hideDatePicker} />

aman5509 commented 2 years ago

Returning one day less on IOS but working fine on Andorid.

ArjunVaskale commented 2 years ago

Basically It's returning time in 24 hours format . So this is how I handled it.

<DateTimePickerModal isVisible={this.state.showDate} mode={"time"} onConfirm={this.onChangeDate} onCancel={this.hideDatePicker} date={new Date()} minuteInterval={1} />

below is my onChangeDate function where I handled this issue.

  onChangeDate = (text: any) => {
    let hours = parseInt(JSON.stringify(text).slice(12, 14)) - 6;
        let minutes = parseInt(JSON.stringify(text).slice(15, 17)) - 30;
        console.warn("befor", hours, text);

        if (minutes < 0) {
          hours = hours - 1;
          minutes = 60 + minutes;
        }
        if (hours < 0) {
          hours = 24 + hours;
        }

        if (hours > 12) {
          hours = hours - 12;
          console.warn(`Time is => ${hours}:${minutes} AM`);
        } else {
          console.warn(`Time is => ${hours}:${minutes} PM`);
        }     
    this.hideDatePicker(); 
 }

Now It's Working fine.

MMikita3026 commented 2 years ago

Having the same issue. Any updates on this?

lakshyamunjal commented 2 years ago

I was facing the same issue but I've come up with a solution. In the callback function for onConfirm, custom logic is dependent on the minuteInterval

const handleConfirm = (date: Date) => {
    const minute =
      Math.floor(date.getMinutes() / MINUTE_INTERVAL) * MINUTE_INTERVAL;
    const newDate = new Date(
      date.getFullYear(),
      date.getMonth(),
      date.getDate(),
      date.getHours(),
      minute,
    );
    // update component state
    setStartTime(newDate);
  };

Hope this helps :)

PRAxISDEVELOPMENT commented 2 years ago

add date={new Date()} See below;

return ( <DateTimePickerModal mode="time" isVisible={visible} minimumDate={minDate ? minDate : new Date()} date={minDate ? minDate : new Date()} onChange={onChange} is24Hour={true} minuteInterval={minuteInterval} maximumDate={maxDate} locale={Localization.locale} confirmTextIOS={${t(Confirm)}} cancelTextIOS={${t(Cancel)}} onConfirm={confirmHandler} onCancel={cancelHandler} textColor="black" /> );

chideraike commented 2 years ago

Returning one day less on IOS but working fine on Android.

I have the same issue. How do I fix it?