11

问题

如果我在 a 中选择一个日期<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 日期时间。

我试过的

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

4 回答 4

5

材质 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>
    )
  }
}

有了这个,你有2个选择。

1)您可以将其直接挂钩到 redux 并在两者都被选中时拍摄动作。

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

2)编写自己的输入组件

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

于 2017-07-05T12:53:41.410 回答
1

最简单的选择是设置一个自定义函数作为其parse属性<DateInput>,允许在进入 Redux 存储之前对其值进行操作。

const dateString = v => {
  if (isNaN(v)) return;

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

  return adjustedDate;
};

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

这在 Admin-on-rest文档中有描述,更多信息可以在关于Value Lifecycle Hooks的 Redux 表单文档中找到。

注意感谢 kunal pareek关于如何在其他高级答案中修复时区偏移的建议。

更新:这在 Admin-on-rest 的当前版本(截至 08/2018)中可能无法正常工作。请参阅Tomasz Madeyski 的回答和/或查看已解决问题的文档。

于 2017-07-06T16:05:44.787 回答
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>
于 2021-06-18T06:40:43.937 回答
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} />
于 2018-08-03T07:39:12.897 回答