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

PWA课程日历跨月排序问题:如何实现[27,28,1,2,3]排序?

解决跨月周课程日历的日期排序问题

我开发了一个PWA课程日历,常规日期下课程显示正常,但遇到跨月的周时,会出现日期排序错误——比如周一的课程被显示到了周四。目前生成的日期键排序是[1,2,3,27,28],但实际需要按周的顺序排列成[27,28,1,2,3]。

现有JSON结构示例

{
  "27": [
    {
      "day": 27,
      "isLesson": true,
      "start": "16:00",
      "end": "17:00",
      "room": "myRoom",
      "prof": "myTeacher",
      "spe": "MySpe"
    },
    {
      "day": 27,
      "isLesson": true,
      "start": "14:15",
      "end": "15:45",
      "room": "myRoom",
      "prof": "myTeacher",
      "spe": "MySpe"
    },
    {
      "day": 27,
      "isLesson": true,
      "start": "13:45",
      "end": "14:15",
      "room": "myRoom",
      "prof": "myTeacher",
      "spe": "MySpe"
    }
  ],
  "28": [
    {
      "day": 28,
      "isLesson": true,
      "start": "09:00",
      "end": "10:00",
      "room": "myRoom",
      "prof": "myTeacher",
      "spe": "MySpe"
    },
    { "isLesson": false, "start": "10:00", "end": "13:45" },
    {
      "day": 28,
      "isLesson": true,
      "start": "13:45",
      "end": "15:45",
      "room": "myRoom",
      "prof": "myTeacher",
      "spe": "MySpe"
    }
  ]
}

现有arrange函数代码

function arrange(json) {
  let new_json = {};
  let previousSession = {};
  for (const [uid, session] of Object.entries(json)) {

   
    if (!uid.match(/^[\d-]*$/))
    {
      continue;
    }
    
    let minMidi = new Date(session.start);
    minMidi.setHours(11, 15, 0);
    let maxMidi = new Date(session.start);
    maxMidi.setHours(12, 45, 0);
    
    let session_json = {};
    session_json.day = new Date(session.dtstamp).getDate();
    
    if (previousSession.end && minMidi >= previousSession.end && previousSession.start && maxMidi <= session.start)
    {
      let pause_json = {};
      pause_json.isLesson = false;
      pause_json.start = previousSession.end.toLocaleTimeString('fr-FR', localStringOpt);
      pause_json.end = session.start.toLocaleTimeString('fr-FR', localStringOpt);

      new_json[session_json.day] = new_json[session_json.day] ?? [];
      new_json[session_json.day].push(pause_json);

    }
    session_json.isLesson = true;
  
    const start = new Date(session.start);
    previousSession.start = start;
    session_json.start = start.toLocaleTimeString('fr-FR', localStringOpt);
  
    const end = new Date(session.end);
    previousSession.end = end;
    session_json.end = end.toLocaleTimeString('fr-FR', localStringOpt);
      
    //[...]

    new_json[session_json.day] = new_json[session_json.day] ?? [];
   
    new_json[session_json.day].push(session_json);

  }
  console.log(new_json);
  return Object.values(new_json);
}

解决思路与修改方案

问题出在Object.values(new_json)会按对象键的升序返回值,跨月时小日期(1、2、3)会排在大日期(27、28)前面,不符合周的实际顺序。

方案一:基于日期阈值的排序

通过判断日期范围识别跨月场景,调整排序逻辑:

// 替换原函数末尾的return Object.values(new_json);部分
// 获取所有日期键并转为数字
const dayKeys = Object.keys(new_json).map(Number);

// 排序逻辑:处理跨月周
const sortedKeys = dayKeys.sort((a, b) => {
  // 判断是否是跨月场景:同时存在月初小日期(<=7)和月末大日期(>=25)
  const hasSmallDate = dayKeys.some(day => day <= 7);
  const hasLargeDate = dayKeys.some(day => day >= 25);
  
  if (hasSmallDate && hasLargeDate) {
    // 月末日期排前面,月初日期排后面
    if (a >= 25 && b < 7) return -1;
    if (a < 7 && b >= 25) return 1;
  }
  // 非跨月场景正常升序排列
  return a - b;
});

// 按排序后的键生成结果数组
const sortedResult = sortedKeys.map(key => new_json[key]);

console.log(sortedResult);
return sortedResult;

方案二:基于实际月份的精准排序

如果需要更准确的判断,可以结合session.dtstamp获取完整月份信息,区分上月和下月的日期:

// 替换原函数末尾的return Object.values(new_json);部分
// 为每个日期键绑定对应的月份信息
const dayWithMonth = Object.entries(new_json).map(([key, data]) => {
  // 取该日期下第一个有效课程的dtstamp获取月份
  const validSession = data.find(item => item.day !== undefined);
  const month = new Date(validSession?.dtstamp || session.dtstamp).getMonth();
  return {
    day: Number(key),
    month,
    data
  };
});

// 按月份排序,同月内按日期升序;上月日期排前面,下月日期排后面
dayWithMonth.sort((a, b) => {
  if (a.month !== b.month) {
    return a.month - b.month;
  }
  return a.day - b.day;
});

const sortedResult = dayWithMonth.map(item => item.data);

console.log(sortedResult);
return sortedResult;

说明

  • 方案一的日期阈值(25和7)是常规跨月周的经验值,可根据实际日历规则调整。
  • 方案二更精准,依赖实际月份信息,避免阈值判断的误差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:12:03