react-native-modal-datetime-picker icon indicating copy to clipboard operation
react-native-modal-datetime-picker copied to clipboard

iOS TimePicker - default date actually return the launch date

Open ancyrweb opened this issue 3 years ago • 10 comments

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}
      />

ancyrweb avatar Jun 23 '21 00:06 ancyrweb

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?

mmazzarolo avatar Jun 23 '21 07:06 mmazzarolo

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 :)

ancyrweb avatar Jun 23 '21 09:06 ancyrweb

I'm getting the same issue.

vini-zapid avatar Jun 24 '21 00:06 vini-zapid

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} />

ArpitFuturism avatar Jun 25 '21 08:06 ArpitFuturism

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

aman5509 avatar Dec 29 '21 16:12 aman5509

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.

ArjunVaskale avatar Feb 09 '22 07:02 ArjunVaskale

Having the same issue. Any updates on this?

MMikita3026 avatar Apr 18 '22 09:04 MMikita3026

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 :)

lakshyamunjal avatar May 24 '22 09:05 lakshyamunjal

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" /> );

PRAxISDEVELOPMENT avatar Jul 06 '22 10:07 PRAxISDEVELOPMENT

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

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

chideraike avatar Sep 08 '22 23:09 chideraike