MUI X日期选择器在Azure上选中日期差一天问题求助
我基于Material UI和Formik开发了一个自定义日期选择器组件,用于向父表单组件传递日期值,代码如下:
import React from 'react'; import { useField } from 'formik'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import enGB from 'date-fns/locale/en-GB'; import { parseISO } from 'date-fns'; const CustomDateField = ({ name, label, error, helperText, ...props }) => { const [field, meta, helpers] = useField(name); const locale = enGB; const handleDateChange = (date) => { console.log('date before changes',date) //this if/else logic is redundant as MUI always passes the data as a date, not a string if (typeof date === 'string') { const parsedDate = parseISO(date); console.log('parsedDate',parsedDate) helpers.setValue(parsedDate); } else { helpers.setValue(date); console.log('setValueDate',date) } }; return ( <div className="pb-4"> <LocalizationProvider dateAdapter={AdapterDateFns} adapterLocale={locale}> <DatePicker {...field} {...props} name={name} label={label} value={field.value || null} onChange={handleDateChange} sx={{ width: '100%', }} slotProps={{ textField: { variant: 'outlined', error: Boolean(meta.touched && meta.error), //error handling helperText: meta.touched && meta.error ? meta.error : helperText, }, }} //error handling /> </LocalizationProvider> </div> ); }; export default CustomDateField;
本地开发环境运行时,日期选择器选中的日期能正确传递给父组件,但部署到Azure应用服务后,传递到父组件的日期比选中日期早一天。
日志显示,当选中英国格式日期05/08/2023时,'date before changes'的日志输出为:Date Sat Aug 05 2023 00:00:00 GMT+0100 (British Summer Time),但传递到父组件后变为:"event_date":"2023-08-04T23:00:00.000Z"。
我已尝试将Linux版Azure应用服务器的时区通过AzureApplication Setting配置为TZ=Europe/London(与本地PC时区一致),但问题未解决。也了解过JavaScript date对象导致的类似问题,但本地运行正常仅Azure出问题,因此怀疑并非该原因。
解决思路
1. 统一日期传递格式,规避Date对象序列化时区问题
问题本质是JSON序列化Date对象时会强制转为UTC时间:你选中的英国夏令时(GMT+1)8月5日0点,转成UTC就是8月4日23点,父组件直接序列化Date对象就会出现偏差。
修改handleDateChange,将Date对象转为YYYY-MM-DD格式的字符串传递,彻底消除时区影响:
import { format } from 'date-fns'; // 引入date-fns的format方法 const handleDateChange = (date) => { if (date) { // 转为纯日期字符串,不含时区信息 const dateStr = format(date, 'yyyy-MM-dd'); helpers.setValue(dateStr); } else { helpers.setValue(null); } };
后续父组件拿到的是"2023-08-05"这类字符串,无需处理时区转换。
2. 检查Formik表单提交的序列化逻辑
如果父组件直接用JSON.stringify序列化Formik的values提交,必须手动处理日期字段:
// 示例:在Formik的onSubmit中处理日期 const handleSubmit = (values) => { const processedValues = { ...values, event_date: values.event_date ? format(values.event_date, 'yyyy-MM-dd') : null }; // 提交处理后的processedValues };
确保日期字段以字符串格式传递,而非原始Date对象。
3. 修正组件的value解析逻辑
当前代码中field.value可能存在字符串/Date对象混合的情况,统一解析为Date对象避免渲染异常:
value={field.value ? (typeof field.value === 'string' ? parseISO(field.value) : field.value) : null }
4. 针对SSR场景检查服务器端时区
如果你的应用是服务器端渲染(比如Next.js部署在Azure),服务器端渲染时的时区可能影响日期初始化。可以在SSR环节强制将日期转为指定时区的格式,或者确保前端初始化时用浏览器时区解析日期。
内容的提问来源于stack exchange,提问作者Jess

