日期选择器:时区转移

时间:2017-07-05 10:34:27

标签: material-ui admin-on-rest

问题

如果我在<DateInput>中选择日期,则日期时间位于用户的时区(例如 2017-07-01T00:00:00.000 + 02:00 ),但是当它被发送时到服务器,它转换为UTC,因此结束为 2017-06-30T22:00:00.000Z ,一天后。

底层后端不知道用户的时区,并且在剥离错误日期结束时间之后无法将日期转移回去。

什么能解决我的问题

任何这些选项都可以正常工作:

  1. 使用用户的时区发送日期时间。
  2. 日期时间以天真(=无时区)发送。
  3. 用户选择的日期已被视为UTC。
  4. 仅发送日期( 2017-07-01 ),而不是ISO日期时间。
  5. 我尝试了什么

    • 我查看了Admin-on-rest的DateInput documentation,但没有找到任何改变行为的选项。
    • 我查看了相关的Material-UI的documentation,唯一有点相关的选项似乎是DateTimeFormat但是尽管经历了几次尝试,但我无处可去。
    • 我检查了其他答案,例如Material UI Time Picker UTC,但无法弄清楚如何应用建议的解决方案。

4 个答案:

答案 0 :(得分:3)

材质UI日期和时间选择器返回本地值。您可以在其onChange函数中编写函数,以将日期重新格式化为任何值。

  handleTimeInput = (event, time) => {
    this.setState({
      time: time
    })
  }

然后,您可以使用下面的简单函数重置发送到服务器的时间,将本地时间转换为UTC

export default (date) => {
  return new Date(date.getTime() + date.getTimezoneOffset()*60000)
}

(用于显示)

export default (date) => {
  const tempDate = new Date(date)
  return new Date(tempDate.getTime() - tempDate.getTimezoneOffset()*60000)
}

这是我的comp的整个组件代码。

class DateTimePicker extends Component {
  constructor(props) {
    super(props);
    this.state = {
      date: null,
      time: null
    };
  }
  handleDateInput = (event, date) => {
    this.setState({
      date: date
    })
  }
  handleTimeInput = (event, time) => {
    this.setState({
      time: time
    })
  }
  componentDidUpdate(prevProps, prevState) {
    const {setSchedule, channel} = this.props
    if (prevState.date !== this.state.date || prevState.time !== this.state.time) {
      if (this.state.date && this.state.time) {
        setSchedule(convertISTtoUTC(concatenateDateAndTime(this.state.date, this.state.time)), channel)
      }
    }
  }
  render() {
    return (
      <div >
          <DatePicker autoOk={true} onChange={this.handleDateInput} />
          <TimePicker autoOk={true} pedantic={true} onChange={this.handleTimeInput} />
      </div>
    )
  }
}

有了这个你有两个选择。

1)你可以直接将它连接到redux并在选择两者时进行动作。

https://marmelab.com/admin-on-rest/Actions.html

2)编写自己的输入组件

https://marmelab.com/admin-on-rest/Inputs.html#writing-your-own-input-component

答案 1 :(得分:2)

最简单的选择是将自定义函数设置为parse的{​​{1}}属性,允许在进入Redux存储之前操作该值。

<DateInput>

管理员休息documentation中对此进行了描述,有关详细信息,请参阅Value Lifecycle Hooks上的Redux表单文档。

注意:有关如何在其他高级答案中修复时区偏移量的建议,则会转到kunal pareek

更新:这可能无法在Admin-on-rest的当前版本(截至08/2018)中正常运行。请参阅Tomasz Madeyski的answer和/或查看问题所在的文档addressed

答案 2 :(得分:0)

好吧,由于编辑不应该改变作者的意图,而且编辑时间太长,因此我根据tmt answer添加自己的答案:

可以选择使用parse部分,但函数本身有问题(请参阅代码中的注释以了解原因):

const dateString = v => {
  /* 
  * since v parameter coming is a string then you cannot use isNan 
  * undefined is also coming as a parameter so !v is good equivalent
  */
  if (!v) return; 

  let parsedDate = new Date(v);
  let adjustedDate = new Date(parsedDate.getTime() - parsedDate.getTimezoneOffset() * 60000);

  /*
  * since parameter coming in is a string you need to pass string further, that's why I added toISOString() call
  */
  return adjustedDate.toISOString();
};

<DateInput source="your_date" parse={dateString} />

答案 3 :(得分:0)

只需将时刻设置为特定时区并使用时刻初始化材料 ui 选择器,然后 da da .. 它将起作用..

import moment from 'moment-timezone';
import MomentUtils from '@date-io/moment';
import {DatePicker, MuiPickersUtilsProvider} from '@material-ui/pickers';

useEffect(()=>{
    moment.tz.setDefault('Asia/Kolkata');
},[])

<MuiPickersUtilsProvider libInstance={moment} utils={MomentUtils}>
               <DatePicker
                  variant='inline'
                  autoOk
                  label=''
                  disableToolbar
                  disableFuture
                  format='MM/DD/YYYY'
                  value={selectedDay}
                  onChange={(day) => {
                    const date = moment(day).format('MM/DD/YYYY');
                    setCurrentDay(date);
                    handleDayChange(day);
                  }}
                  InputProps={{
                    disableUnderline: true,
                    style: {
                      backgroundColor: 'white',
                      paddingLeft: 10,
                      borderRadius: 5,
                      width: 160,
                    },
                    endAdornment: (
                      <InputAdornment position='end'>
                        <CalendarTodayIcon style={{paddingRight: 8}} />
                      </InputAdornment>
                    ),
                  }}
                />
              </MuiPickersUtilsProvider>