给卡帕多奇亚民宿做预订页,我把时区算错了一整天

卡帕多奇亚那家洞穴民宿的老板要一个预订页,能选日期、看空房、提交订单。我拿到需求的时候心想这不就是个日期选择器嘛,三天能搞定。结果上线第一天,老板发消息:有个客人订了 14 号的房,但系统显示 13 号入住。

环境是 Node 18 + Express + SQLite,前端用原生 JS 搭的日期选择器,土耳其时区是 UTC+3。我图省事,日期全用 new Date() 存,没做时区转换。结果服务器跑在 UTC 时区,new Date('2024-06-14') 解析成 UTC 零点,存进数据库就是 6 月 13 日 21:00(伊斯坦布尔时间)。客人选 14 号,系统以为是 13 号晚上到,空房表也跟着错位。

我的做法是:前端传日期字符串(YYYY-MM-DD),后端一律用字符串处理,不构造 Date 对象。代码片段:

// 后端接收日期
app.post('/booking', (req, res) => {
  const { checkin, checkout } = req.body;
  // 直接存字符串,避免时区转换
  db.run('INSERT INTO bookings (checkin, checkout) VALUES (?, ?)', [checkin, checkout]);
});

前端日期选择器也改成返回字符串:

function getDateString(date) {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  return `${y}-${m}-${d}`;
}

为什么这样做?因为民宿的预订本质是「日历日」概念,不是精确时间点。客人说 14 号入住,指的就是 14 号那天,跟服务器在哪个时区没关系。用字符串存,数据库里就是 2024-06-14,查空房直接字符串比较,不会因为时区偏移变成 13 号。代价是失去了 Date 对象的时间计算能力,比如算入住天数得自己写函数,但换来的是不会莫名其妙差一天。

哪里会失效?如果民宿以后要精确到小时(比如下午 2 点后入住),字符串就不够用了,得存带时区的时间戳。还有跨年的时候,getFullYear() 在本地时区是对的,但如果用户浏览器时区不是土耳其,可能会差一天——不过我的客人基本都是土耳其本地或欧洲游客,暂时没遇到。我自己踩过的坑是:一开始用 toISOString() 转字符串,结果它永远返回 UTC 时间,又差了一天。后来改成手动拼 getFullYear 这些方法才稳。

现在这个预订页跑了两个月,没再出过日期错位。但我总在想,如果以后要加「提前一天提醒」的功能,字符串存法会不会又让我掉坑里?你们做预订类项目的时候,日期是存字符串还是时间戳?有没有更省心的方案?

0
赞同度 100% · 0 条评论 · 1 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。