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

MERN预约应用UTC转换问题:星期值计算异常排查

问题:Date.getDay() 返回值不符合预期(周日被解析为6而非0)

我正在开发MERN预约应用,调用/available-times?date=2024-03-03接口时,终端显示计算出的dayOfWeek为6,但2024-03-03实际是周日,预期值应为0,导致无法从availability表获取对应时段。当前appointments表为空,接口代码及终端输出如下:

// get available slots
app.get('/available-times', (req, res) => {
  const { date } = req.query;
  if (!date) {
    return res.status(400).send('Date query parameter is required');
  }

  const inputDate = new Date(date);
  const dayOfWeek = inputDate.getDay();

  const sqlAvailabilities = 'SELECT * FROM availability WHERE weekday = ?';

  db.query(sqlAvailabilities, [dayOfWeek], (err, availabilityResults) => {
    if (err) {
      return res.status(500).json({ error: err.message });
    }

    const sqlAppointments = 'SELECT * FROM appointments WHERE date = ?';
    db.query(sqlAppointments, [date], (err, appointmentResults) => {
      if (err) {
        return res.status(500).json({ error: err.message });
      }

      // Create one-hour increments from availability spans
      const oneHourIncrements = availabilityResults.flatMap(avail => {
        const increments = [];
        const startTime = new Date(`1970-01-01T${avail.start_time}`);
        const endTime = new Date(`1970-01-01T${avail.end_time}`);

        while(startTime < endTime) {
          const endIncrement = new Date(startTime.getTime());
          endIncrement.setHours(endIncrement.getHours() + 1);

          increments.push({
            start: startTime.toISOString().split('T')[1].substring(0, 5),
            end: endIncrement.toISOString().split('T')[1].substring(0, 5),
          });

          // Move to next hour
          startTime.setHours(startTime.getHours() + 1);
        }

        return increments;
      });

      // Filter out booked slots
      const availableTimes = oneHourIncrements.filter(increment => {
        return !appointmentResults.some(app => {
          const appStart = `1970-01-01T${app.start_time}`;
          const appEnd = `1970-01-01T${app.end_time}`;
          const incStart = `1970-01-01T${increment.start}`;
          const incEnd = `1970-01-01T${increment.end}`;
          return (incStart < appEnd) && (incEnd > appStart);
        });
      });

      console.log('Received date:', date);
      console.log('Calculated dayOfWeek:', dayOfWeek);
      console.log('Availability results:', availabilityResults);
      console.log('Appointment results:', appointmentResults);
      console.log('One-hour increments:', oneHourIncrements);
      console.log('Available Times:', availableTimes);
      res.json(availableTimes);
    });
  });
});

终端输出:

Received date: 2024-03-03
Calculated dayOfWeek: 6
Availability results: []
Appointment results: []
One-hour increments: []
Available Times: []


问题原因

JavaScript中,当使用new Date('YYYY-MM-DD')这种ISO格式字符串构造日期时,默认会以UTC时区解析。如果你的本地时区比UTC早(比如东八区),2024-03-03会被解析为UTC时间的2024-03-03T00:00:00Z,对应本地时区的2024-03-02T16:00:00(假设UTC-8),此时getDay()返回的是周六的6,而非预期的周日0。

修复方案

有两种可靠的方式确保日期以本地时区解析:

方案1:拆分日期字符串,用年、月、日参数构造Date

将日期字符串拆分为年、月、日,直接传入Date构造函数(注意月份是0-based,需要减1):

const { date } = req.query;
if (!date) {
  return res.status(400).send('Date query parameter is required');
}

// 拆分日期,按本地时区构造Date
const [year, month, day] = date.split('-').map(Number);
const inputDate = new Date(year, month - 1, day); // 月份从0开始,所以减1
const dayOfWeek = inputDate.getDay();

方案2:调整UTC时间到本地时区

通过时区偏移量修正解析后的日期:

const inputDate = new Date(date);
// 加上时区偏移量,将UTC时间转为本地时间的日期
inputDate.setMinutes(inputDate.getMinutes() + inputDate.getTimezoneOffset());
const dayOfWeek = inputDate.getDay();

验证与后续检查

  1. 修改代码后,重新调用接口,dayOfWeek应返回0(对应周日)。
  2. 确认availability表中,周日对应的weekday字段值为0,确保数据库数据与代码逻辑匹配。

内容的提问来源于stack exchange,提问作者nodenewbie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:37:30