react-native-datepicker icon indicating copy to clipboard operation
react-native-datepicker copied to clipboard

Select one day, but selected one day +1. IOS

Open nickorsk2017 opened this issue 8 years ago • 14 comments

Select 28 october 1985, but selected 29 october 1985 Platform: IOS. How rule this problem? Thanks.

nickorsk2017 avatar Mar 07 '17 17:03 nickorsk2017

I'm having the same issue. Using:

          <DatePicker style={[styles.inputField, styles.inputDatePicker]}
                      mode="date"
                      format="MMMM Do YYYY"
                      date={this.state.birth_date}
                      confirmBtnText="Confirm"
                      cancelBtnText="Cancel"
                      showIcon={false}
                      onDateChange={(strDate, date) => this.setState({'birth_date': date})} />

where the initial birth_date in state is moment().utc().toDate(). I have this happen without setting an initial date too.

On debug builds, everything is fine. The value selected in the DatePicker is the value I see when I hit "Confirm".

On Release builds, hitting "Confirm", the value returned isn't always the value in the DatePicker.

Sometimes it is, sometimes it's off by one year, sometimes it's off by one day. I haven't had this happen on an Android ever, but I've had this happen on Release mode in iOS simulators and iPhones (a 6s running iOS 10).

If I select March 14, 1992, value displayed in the DatePicker after I hit "confirm" is March 15, 1992, alongside the value passed to the DatePicker's onDateChange. This doesn't happen on every release build, nor does it occur for every date. But when it occurs, it's consistently off by one.

For now I'm switching over to using DatePickerIOS manually on my iOS builds, but this library works great for me on Android.

jc4p avatar Mar 22 '17 05:03 jc4p

i am having the same problem. it is minus one day for me on IOS.

isbaek avatar Mar 22 '17 19:03 isbaek

I was having similar problems trying to use "MMMM Do YYYY" on iOS. Trying to set 'Jan 1 2000' returns 'Jan 4 2000' or 'Jan 1 2001' for example. The built-in "YYYY-MM-DD" format seemed to work fine.

I found if I explicitly set minDate and maxDate props in "MMMM Do YYYY" format it would work correctly.

var localizedFormat = "MMMM Do YYYY";
var maxDateString = moment().format(localizedFormat); //Today
var minDateString = moment('19000101','YYYYMMDD').format(localizedFormat); //Jan 1 1900
...
<DatePicker
    format={localizedFormat}
    maxDate={maxDateString}
    minDate={minDateString}
    ...
/>

Proberts avatar Apr 10 '17 09:04 Proberts

I can confirm @Proberts suggestion above appears to be a solution. Explicitly setting the minDate/maxDate in the format of the picker seems to fix this problem.

caddac avatar Apr 17 '17 11:04 caddac

@Proberts' solution didn't work for me, I fixed it by setting up the timeZoneOffsetInHours prop.

__constructor(props) {
    super(props)

    this.state = {
        timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
        birthdate: props.birthdate
    }
}

render() {
    ...
                <DatePicker
                    date={this.state.birthdate}
                    mode='date'
                    format={localizedFormat}
                    maxDate={maxDateString}
                    minDate={minDateString}
                    timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
                    ...
                  />
    ...
}

andruxnet avatar May 31 '17 17:05 andruxnet

I am still having the same issues on both iOS and Android after implementing @Proberts and @andruxnet 's solutions. The observation is that this issue will trigger for dates equals or earlier than year 1981.

Does anyone else has a solution ?

infinitey avatar Jan 12 '18 04:01 infinitey

I fixed it by creating a new date object using .getUTC...() and including time

Example:

const date = new Date();
const dateForPicker = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());

via https://stackoverflow.com/a/14006555/7569308

jayporta avatar May 04 '18 16:05 jayporta

@andruxnet Thank you! This is such a bizarre issue, and still affecting the latest version of react-native. Your hack fixed it for me.

andrewzey avatar Nov 01 '18 03:11 andrewzey

I can confirm that even with @andruxnet's fix, it's still happening on some random dates.

andrewzey avatar Dec 15 '18 20:12 andrewzey

@andruxnet You solution is correct but it only work for iOS. This issue is also for android but android date picker doesn't support timeZoneOffsetInMinutes prop. now!

mohsinnaqvi110 avatar Dec 18 '18 06:12 mohsinnaqvi110

onDateChange={date => this.setState({ birth_date: new Date(date) }) }

to

onDateChange={date => this.setState({ birth_date: moment(date) }) }

did the trick for me.

ALawliet avatar Feb 23 '19 03:02 ALawliet

@Proberts' solution didn't work for me, I fixed it by setting up the timeZoneOffsetInHours prop.

__constructor(props) {
    super(props)

    this.state = {
        timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
        birthdate: props.birthdate
    }
}

render() {
    ...
                <DatePicker
                    date={this.state.birthdate}
                    mode='date'
                    format={localizedFormat}
                    maxDate={maxDateString}
                    minDate={minDateString}
                    timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
                    ...
                  />
    ...
}

@Proberts seems to be onto the right track. However; there is a caveat here that i found that might be the reason why it doesn't work for everyone.

Daylight savings time. and how you are calculating the offset.

First, if you set the offset as a static value you are going to run into problems. The gist of what happens here. Is that when you change from dates that go across a daylight savings time. The offset of the internal datepicker object changes. from in my case -7 to -6, and if you dont update your calculated offset based on that change (IE the internal state of the datepicker) then you are going to go from -7 to -6 which would cross a date barrier in my case.

you can see this in action on the snack that i have linked below. There is a toggle option that uses the compenents date value to calculate the offset vs the date set by the DatePikcerIOS date.

its an odd problem to be sure.

    timeZoneOffsetInMinutes={
        ( (-1) * (new Date(this.props.date)).getTimezoneOffset() / 60 ) * 60
    }

Heres is a snack of what i tested. although the offset sometimes doenst register maybe the emulated device is in a DST free zone?

It is very important here to set the initialDate of the internal iOS component to the internal state of the your wrapping component, and make sure your offset matches the initial date set on the compeonent. otherwise you will see odd things happen when the picker mounts in one offset but you set it to another. use the snack below and change the initial date from this.state.date to this.props.date and you will see what i mean.

https://snack.expo.io/ByceqT-6V

christianallred avatar May 21 '19 17:05 christianallred

I don't understand only one thing. What is the purpose of dividing minutes by 60 to get hours and then multiplying by 60 to get minutes back.

Instead of

timeZoneOffsetInMinutes={
        ( (-1) * (new Date(this.props.date)).getTimezoneOffset() / 60 ) * 60
 }

You could simply use

timeZoneOffsetInMinutes={
        -1 * new Date(this.props.date).getTimezoneOffset()
}

anjmao avatar Nov 04 '19 19:11 anjmao

@Proberts' solution didn't work for me, I fixed it by setting up the timeZoneOffsetInHours prop.

__constructor(props) {
    super(props)

    this.state = {
        timeZoneOffsetInHours: (-1) * (new Date()).getTimezoneOffset() / 60,
        birthdate: props.birthdate
    }
}

render() {
    ...
                <DatePicker
                    date={this.state.birthdate}
                    mode='date'
                    format={localizedFormat}
                    maxDate={maxDateString}
                    minDate={minDateString}
                    timeZoneOffsetInMinutes={this.state.timeZoneOffsetInHours * 60}
                    ...
                  />
    ...
}

i don't know why but when i add a very large number it works. Can you explain what this : timeZoneOffsetInMinutes? does?

9nuh avatar Dec 07 '21 17:12 9nuh