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

如何在前端将全年日期按月份与周进行分组?

按年、月、周分组日期数组的实现方案

理想情况下这类分组操作应该在后端渲染前完成,但我的业务场景里做不到,所以想问能不能把一整年的日期按月份和周进行分组?

原始日期数组示例

const dates = [
  {
    id: 1,
    date: '2022-01-01'
  },
  {
    id: 2,
    date: '2022-01-02'
  },
  {
    id: 3,
    date: '2022-01-03'
  },
  {
    id: 4,
    date: '2022-01-04'
  },
  {
    id: 5,
    date: '2022-01-05'
  },
  // ... 省略中间355条日期数据
  {
    id: 361,
    date: '2022-12-27'
  },
  {
    id: 362,
    date: '2022-12-28'
  },
  {
    id: 363,
    date: '2022-12-29'
  },
  {
    id: 364,
    date: '2022-12-30'
  },
  {
    id: 365,
    date: '2022-12-31'
  },
];

期望的分组结构

树形展示

├── 一月(January)
│   ├── 52
│   │   ├── 2022-01-01
│   │   └── 2022-01-02
│   ├── 1
│   │   ├── 2022-01-03
│   │   ├── 2022-01-04
│   │   ├── 2022-01-05
│   │   ├── 2022-01-06
│   │   ├── 2022-01-07
│   │   ├── 2022-01-08
│   │   └── 2022-01-09
│   ├── 2
│   │   └── ...
│   ├── 3
│   │   └── ...
│   └── 4
│       └── ...
├── 二月(February)
│   ├── 5
│   │   └── ...
│   ├── 6
│   │   └── ...
│   ├── 7
│   │   └── ...
│   └── 8
│       └── ...
└── 三月(March)
    ├── 9
    │   └── ...
    ├── 10
    │   └── ...
    ├── 11
    │   └── ...
    └── 12
        └── ...

具体对象结构示例

const sortedDates = {
    2022: {
        january: {
            51:{
                '2022-01-01': {
                    sunday: false
                },
                '2022-01-02': {
                    sunday: true
                }
            },
            1:{
                '2022-01-03': {
                    sunday: false
                },
                '2022-01-04': {
                    sunday: false
                },
                '2022-01-05': {
                    sunday: false
                },
                '2022-01-06': {
                    sunday: false
                },
                '2022-01-07': {
                    sunday: false
                },
                '2022-01-08': {
                    sunday: false
                },
                '2022-01-09': {
                    sunday: true
                },
            }
        },
        february: {
            // 对应二月的周分组数据
        }
    }
}

前端实现方案

可以通过JavaScript直接处理完成分组,核心是解析每个日期的年份、月份名称、周数,同时判断是否为周日,逐步构建目标结构。

完整代码

// 月份名称映射(小写,匹配目标结构的键)
const monthNames = [
  'january', 'february', 'march', 'april', 'may', 'june',
  'july', 'august', 'september', 'october', 'november', 'december'
];

// 获取日期的ISO周数(ISO周以周一为起始,一年第一周至少包含4天)
const getWeekNumber = (date) => {
  const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
  const dayNum = d.getUTCDay() || 7; // 将周日转为7,统一计算逻辑
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  return Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
};

// 执行分组逻辑
const groupDatesByYearMonthWeek = (dates) => {
  const result = {};

  dates.forEach(item => {
    const dateObj = new Date(item.date);
    const year = dateObj.getFullYear();
    const monthIndex = dateObj.getMonth();
    const monthName = monthNames[monthIndex];
    const weekNumber = getWeekNumber(dateObj);
    const isSunday = dateObj.getDay() === 0; // 0代表周日

    // 逐层创建嵌套结构,避免不存在的层级报错
    if (!result[year]) result[year] = {};
    if (!result[year][monthName]) result[year][monthName] = {};
    if (!result[year][monthName][weekNumber]) result[year][monthName][weekNumber] = {};

    // 存入当前日期的信息,可扩展添加原对象的其他字段
    result[year][monthName][weekNumber][item.date] = {
      sunday: isSunday,
      id: item.id // 可选:保留原数据的id字段
    };
  });

  return result;
};

// 使用示例
const sortedDates = groupDatesByYearMonthWeek(dates);
console.log(sortedDates);

关键说明

  • 周数计算:采用ISO周标准,确保周数符合国际通用规则(比如2022年1月1日属于2021年的第52周),如果需要以周日为一周起始的规则,可调整getWeekNumber函数的逻辑。
  • 层级构建:通过判断每一层级是否存在,逐步创建年、月、周的嵌套结构,避免直接赋值不存在的属性导致报错。
  • 字段扩展:如果需要保留原日期对象的其他字段(如id),直接在存入时添加到对应的对象中即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 14:25:29