You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Yup校验使用MUI X DateTimePicker并限制起止日期范围

问题描述

当前使用React Hook Form结合MUI DateTimePicker实现起止日期选择,必填校验已生效,但用户仍可选择结束日期早于开始日期,需要限制该情况,同时必须保持日期提交格式为UTC。尝试过改用TextField、普通DatePicker及Dayjs均未解决问题。

现有代码
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { DateTimePicker } from "@mui/x-date-pickers";
const schema = Yup.object({
  startDate: Yup.date().required("startDate is required"),
  endDate: Yup.date().required("endDate is required"), 
});
const {
    register,
    control,
    formState: { errors },
    handleSubmit,
    reset,
    watch,
  } = useForm({
    defaultValues: {      
      startDate: "",
      endDate: "",
    },
    mode: "all",
    resolver: yupResolver(schema),
  });
const onSubmit = (data: any) => {  
    data.startDate = new Date(data.startDate).toISOString();
    data.endDate = new Date(data.endDate).toISOString();
};
<div className="grid grid-cols-4 ml-10 mr-56">
        <div>
          <Controller
            name="startDate"
            control={control}
            render={({ field: { onChange, value } }) => (
              <DateTimePicker
                disablePast
                id="startDate"
                label=" Start Date"
                placeholder="Start Date"
                value={value}
                onChange={onChange}
                renderInput={(params) => <TextField {...params} />}
              />
            )}
          />
        </div>
        <div>
          <Controller
            name="endDate"
            control={control}
            render={({ field: { onChange, value } }) => (
              <DateTimePicker
                disablePast
                label=" End Date"
                id="endDate"
                placeholder="End Date"
                value={value}
                onChange={onChange}
                renderInput={(params) => <TextField {...params} />}     
              />
            )}
          />
        </div>
      </div>
解决方案

可以从校验逻辑和组件交互限制两方面入手,同时保留UTC格式:

1. 用Yup添加日期比较校验

修改Yup schema,让结束日期必须晚于开始日期,同时基于UTC时间比较避免时区差异:

const schema = Yup.object({
  startDate: Yup.date().required("startDate is required"),
  endDate: Yup.date()
    .required("endDate is required")
    .test(
      "is-after-start",
      "End date must be after start date",
      function(value) {
        const { startDate } = this.parent;
        if (!startDate || !value) return true; // 空值交给required规则处理
        // 转换为UTC时间戳比较,消除时区影响
        const startUTC = new Date(startDate).setHours(0, 0, 0, 0);
        const endUTC = new Date(value).setHours(0, 0, 0, 0);
        return endUTC > startUTC;
      }
    ),
});

2. 在DateTimePicker中添加交互限制

通过watch监听起始日期,给结束日期选择器设置minDate,让用户无法选择早于起始日期的选项:

// 监听起始日期的实时值
const watchedStartDate = watch("startDate");

// 修改结束日期的Controller渲染逻辑
<Controller
  name="endDate"
  control={control}
  render={({ field: { onChange, value } }) => (
    <DateTimePicker
      disablePast
      label=" End Date"
      id="endDate"
      placeholder="End Date"
      value={value}
      onChange={onChange}
      // 设置最小可选日期为已选的起始日期
      minDate={watchedStartDate ? new Date(watchedStartDate) : null}
      // 绑定错误提示
      renderInput={(params) => <TextField {...params} error={!!errors.endDate} helperText={errors.endDate?.message} />}     
    />
  )}
/>

3. 保留UTC格式

你当前onSubmit方法中把日期转为ISO字符串的逻辑无需修改,ISO字符串本身就是UTC标准格式,能满足需求。

这种方案既通过组件交互限制用户的错误选择,又通过校验逻辑在提交前做二次验证,双重保障解决问题。

内容的提问来源于stack exchange,提问作者MR.T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 17:30:47