日期选择器:时区偏移



>问题

如果我在<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但尽管进行了几次尝试,我还是一无所获。
  • 我检查了其他答案,例如材料 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>

最新更新