>问题
如果我在<DateInput>
中选择一个日期,则日期时间在用户的时区中(例如2017-07-01T00:00:00.000+02:00),但是当它发送到服务器时,它会转换为 UTC,因此最终为2017-06-30T22:00:00.000Z,落后一天。
底层后端不知道用户的时区,并且无法将日期移回,因此在剥离时间后,它最终会得到错误的日期。
什么可以解决我的问题
这些选项中的任何一个都可以正常工作:
- 日期时间与用户的时区一起发送。
- 日期时间作为幼稚发送(=没有时区)。
- 用户选择的日期已被视为 UTC。
- 仅发送日期 (2017-07-01) 而不是 ISO 日期时间。
我尝试了什么
- 我查看了 Admin-on-rest 的
DateInput
文档,但没有找到任何更改行为的选项。 - 我查看了相关的 Material-UI 的文档,唯一有点相关的选项似乎是
DateTimeFormat
但尽管进行了几次尝试,我还是一无所获。 - 我检查了其他答案,例如材料 UI 时间选择器 UTC,但无法弄清楚如何应用建议的解决方案。
材质 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)
}
这是我的合成的整个组件代码。
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
最简单的选择是将自定义函数设置为<DateInput>
的parse
属性,该属性允许在进入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 文档中进行了描述,更多信息可以在关于值生命周期挂钩的 Redux 表单文档中找到。
注意:感谢 kunal pareek 关于如何修复其他高级答案中的时区偏移量的建议。
更新:这在当前版本(截至 2018 年 8 月)的 Admin-on-rest 中可能无法正常工作。请参阅Tomasz Madeyski的回答和/或检查已解决问题的文档。
好吧,由于编辑不应该改变作者的意图,而且编辑时间有点太长了,我根据 tmt 答案添加自己的答案:
使用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} />
只需将时刻设置为特定时区并使用时刻初始化材料 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>