写过前端的都以为全球化只是翻译——今天两个 JS API 把日历首日这件事彻底原生化了

做国际化产品,日历组件几乎人手一个。但你有没有被这些细节卡过:周日还是周一作为一周起始?沙特的周末是周五和周六,不是周六和周日;文莱的周末是周五和周日,中间夹着周六上班。

这些数据以前要么硬编码,要么引入 moment.js / date-fns / date-fns-tz 整一套库来兜着。现在,两个原生 JS API 全部搞定。

问题:全球化日历数据的获取一直是痛点

做多地区日历时,你需要知道:

  • 一周从哪天开始(firstDay)
  • 哪些天是周末(weekend,不一定是连续的
  • 一个月第一周最少需要几天(minimalDays,ISO 8601 用)

历史上:

  • moment.js / date-fns / js-joda 需要引入库
  • date-fns-tz 单独处理时区
  • 硬编码 Map 容易出错,不同地区规则差异超出预期(英国 en-GB 是周一,阿拉伯地区是周六,布隆迪 en-BN 是周五+周日不是周六)

解决方案:Intl.Locale weekInfo

两个 API 同源,选 getWeekInfo() 更规范:

// 一行代码获取任意地区的周信息
const locale = new Intl.Locale('en-GB');
const { firstDay, weekend, minimalDays } = locale.getWeekInfo();

console.log(firstDay);     // 1  (周一)
console.log(weekend);      // [6, 7]  (周六、周日)
console.log(minimalDays);  // 4  (ISO 8601 要求第一周至少4天)

实战示例——根据用户 locale 渲染日历组件:

function getCalendarConfig(localeTag) {
  const { firstDay, weekend, minimalDays } = new Intl.Locale(localeTag).getWeekInfo();
  return {
    weekStart: firstDay,         // 1=周一 ... 7=周日
    weekendDays: new Set(weekend), // [5, 6] 沙特这种不连续也能用
    isoWeekMinDays: minimalDays,
  };
}

// 中国用户
console.log(getCalendarConfig('zh-CN'));
// { weekStart: 1, weekendDays: Set { 6, 7 }, isoWeekMinDays: 1 }

// 英国用户
console.log(getCalendarConfig('en-GB'));
// { weekStart: 1, weekendDays: Set { 6, 7 }, isoWeekMinDays: 4 }

// 沙特阿拉伯
console.log(getCalendarConfig('ar-SA'));
// { weekStart: 6, weekendDays: Set { 5, 6 }, isoWeekMinDays: 1 }

// 文莱——周末不连续!周五和周日,中间夹着周六
console.log(getCalendarConfig('ms-BN'));
// { weekStart: 7, weekendDays: Set { 5, 7 }, isoWeekMinDays: 1 }

配合 Intl.DateTimeFormat 做完整国际化日期

function formatWeekdayHeaders(localeTag) {
  const { firstDay } = new Intl.Locale(localeTag).getWeekInfo();
  const formatter = new Intl.DateTimeFormat(localeTag, { weekday: 'short' });
  const days = [];
  for (let i = 0; i < 7; i++) {
    const dayIndex = (firstDay - 1 + i) % 7;
    const date = new Date(2026, 0, 5 + dayIndex); // 2026-01-05 是周一
    days.push(formatter.format(date));
  }
  return days;
}

console.log(formatWeekdayHeaders('zh-CN'));
// ['周一', '周二', '周三', '周四', '周五', '周六', '周日']

console.log(formatWeekdayHeaders('en-US'));
// ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']  // 美国从周日开始

兼容性与 API 选择

  • Chrome 130+ / Firefox 130+ / Safari 17+ 推荐用 getWeekInfo() 方法
  • 老版本用 locale.weekInfo 访问器属性(行为相同但返回同一引用)
  • 两者返回结构完全一致:{ firstDay, weekend, minimalDays }

结论

Intl.Locale 的 weekInfo 接口让全球化日历数据彻底原生化,不再需要任何第三方库,也不需要维护一份不断膨胀的地区规则 Map。两个属性搞定所有场景,包括那些你以为只有 JS 库才知道的不规则周末。

下一步

  • 打开浏览器控制台跑一下 new Intl.Locale('ar-SA').getWeekInfo(),看看沙特周末是哪两天
  • 把现有日历组件的 weekStart 逻辑从硬编码 Map 替换成这个 API
  • 顺手看一下 Intl.Locale 还有哪些 getter 可以用——hourCyclecalendarnumberingSystem,一个对象全拿回来

评论区

0 条评论

登录后可评论。

阿柯·前端架构 11 阅读