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

如何用JavaScript/ES6将5年日度数据聚合至每月最后一日?

嘿,这个需求其实挺常见的,用ES6的数组方法就能轻松搞定,我给你拆解一下思路和具体代码,保证你能看懂~

首先,核心思路其实很简单:把同一月份的日度数据归为一组,然后在每组里挑出日期最晚的那条(也就是当月最后一天的数据),最后整理成你要的格式就行。

接下来是具体实现,我会一步步给你讲清楚:

第一步:先处理日期解析(避免时区坑)

直接用new Date(dateStr)有时候会因为时区问题出bug,比如你在东八区的话,new Date('2018-01-31')可能会被解析成前一天的UTC时间,导致月份判断错误。所以我们写个辅助函数,用UTC来解析日期:

const parseUtcDate = (dateStr) => {
  const [year, month, day] = dateStr.split('-').map(Number);
  // 月份是0开始的,所以要减1,用Date.UTC确保是UTC时间
  return new Date(Date.UTC(year, month - 1, day));
};

第二步:把日度数据按「年-月」分组

用Array.reduce()来分组,把同一月份的数据放在一起,这样后续处理更方便:

// 假设你的原始日度数据是这个格式
const dailyData = [
  { x: '2018-01-01', y: 10 },
  { x: '2018-01-31', y: 15 },
  { x: '2018-02-28', y: 22 },
  // ... 剩下的5年数据
];

// 按年-月分组
const groupedByMonth = dailyData.reduce((groups, item) => {
  const date = parseUtcDate(item.x);
  const year = date.getUTCFullYear();
  // 把月份转成两位数字(比如1月变成'01'),保证分组key统一
  const month = String(date.getUTCMonth() + 1).padStart(2, '0');
  const groupKey = `${year}-${month}`;

  // 如果这个分组还不存在,就创建一个空数组
  if (!groups[groupKey]) {
    groups[groupKey] = [];
  }
  groups[groupKey].push(item);
  return groups;
}, {});

第三步:从每个分组里提取当月最后一天的数据

每个分组里的日期不一定是按顺序排的,我们用reduce()高效找到日期最晚的那条数据:

const monthlyLastDayData = Object.values(groupedByMonth).map(group => {
  return group.reduce((latestItem, currentItem) => {
    const latestDate = parseUtcDate(latestItem.x);
    const currentDate = parseUtcDate(currentItem.x);
    // 比较两个日期,返回更晚的那个
    return currentDate > latestDate ? currentItem : latestItem;
  });
});

第四步:给结果按时间排序(可选但推荐)

分组后的顺序可能不是严格的时间顺序,所以我们给结果排个序:

monthlyLastDayData.sort((a, b) => parseUtcDate(a.x) - parseUtcDate(b.x));

处理特殊情况:如果当月最后一天的数据缺失怎么办?

如果你的日度数据偶尔有缺失,比如某个月的最后一天没有数据,我们可以先计算出当月的最后一天,再去匹配数据,找不到的话就取当月最晚的那条:

先写个计算当月最后一天的函数:

const getLastDayOfMonth = (year, month) => {
  // month是1-12的数字,Date.UTC(year, month, 0)会返回当月最后一天的UTC时间
  return new Date(Date.UTC(year, month, 0)).getUTCDate();
};

然后修改第三步的代码:

const monthlyLastDayData = Object.entries(groupedByMonth).map(([groupKey, group]) => {
  const [year, month] = groupKey.split('-').map(Number);
  const lastDay = getLastDayOfMonth(year, month);
  // 拼接成当月最后一天的日期字符串,比如'2018-02-28'
  const lastDayStr = `${year}-${month.toString().padStart(2, '0')}-${lastDay.toString().padStart(2, '0')}`;
  // 查找分组里有没有当天的数据
  const targetItem = group.find(item => item.x === lastDayStr);
  // 如果找不到,就取分组里日期最晚的那条
  return targetItem || group.reduce((latest, current) => parseUtcDate(current.x) > parseUtcDate(latest.x) ? current : latest);
});

优化小技巧:减少重复解析日期

如果数据量很大,重复解析日期会有点浪费性能,我们可以先预处理数据,把每个item的日期提前解析好:

// 预处理数据,缓存解析后的日期
const processedDailyData = dailyData.map(item => ({
  ...item,
  utcDate: parseUtcDate(item.x)
}));

// 后续分组和比较的时候直接用utcDate就行,不用再重复解析
const groupedByMonth = processedDailyData.reduce((groups, item) => {
  const year = item.utcDate.getUTCFullYear();
  const month = String(item.utcDate.getUTCMonth() + 1).padStart(2, '0');
  const groupKey = `${year}-${month}`;
  if (!groups[groupKey]) groups[groupKey] = [];
  groups[groupKey].push(item);
  return groups;
}, {});

这样处理后,效率会更高一些~

现在你运行这些代码,就能得到你想要的[{ x: '2018-03-31', y: 27 }, ...]格式的数据啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:02:02