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

MongoDB聚合计算日期差时扣除周日时长的实现方法

解决MongoDB聚合中扣除周日时长的问题

你可以通过计算区间内的周日总数,再从总时长中扣除对应小时数的方式实现需求。以下是两种可行的聚合管道写法:

简洁版(推荐新手使用)

这个版本将所有计算整合在一个$project阶段,逻辑清晰且避免重复代码:

db.collections.aggregate([
  {
    $project: {
      waitTime: {
        $dateDiff: {
          startDate: ISODate("2023-08-10T10:24:51.303Z"),
          endDate: ISODate("2023-08-30T10:24:51.303Z"),
          unit: "hour"
        }
      },
      exceptSundays: {
        $let: {
          vars: {
            start: ISODate("2023-08-10T10:24:51.303Z"),
            end: ISODate("2023-08-30T10:24:51.303Z"),
            dayMs: 1000 * 60 * 60 * 24 // 一天的毫秒数
          },
          in: {
            $subtract: [
              // 总时长(小时)
              {
                $dateDiff: {
                  startDate: "$$start",
                  endDate: "$$end",
                  unit: "hour"
                }
              },
              {
                $multiply: [
                  // 计算区间内的周日数量
                  {
                    $subtract: [
                      // 结束日期对应的完整周数(从纪元开始,每周一个周日)
                      { $floor: { $divide: [{ $toLong: "$$end" }, "$$dayMs" * 7] } },
                      // 开始日期前一天对应的完整周数
                      { $floor: { $divide: [{ $toLong: { $subtract: ["$$start", "$$dayMs"] } }, "$$dayMs" * 7] } }
                    ]
                  },
                  24 // 每个周日扣除24小时
                ]
              }
            ]
          }
        }
      }
    }
  }
])

分步拆解版(适合理解逻辑)

如果需要逐步理解每个计算环节,可以用多个$project阶段拆分:

db.collections.aggregate([
  // 第一步:计算基础数据
  {
    $project: {
      waitTime: {
        $dateDiff: {
          startDate: ISODate("2023-08-10T10:24:51.303Z"),
          endDate: ISODate("2023-08-30T10:24:51.303Z"),
          unit: "hour"
        }
      },
      // 转换日期为毫秒数,方便后续计算
      startMs: { $toLong: ISODate("2023-08-10T10:24:51.303Z") },
      endMs: { $toLong: ISODate("2023-08-30T10:24:51.303Z") }
    }
  },
  // 第二步:计算周日总数
  {
    $project: {
      waitTime: 1,
      totalSundays: {
        $subtract: [
          { $floor: { $divide: ["$endMs", 1000*60*60*24*7] } },
          { $floor: { $divide: [{ $subtract: ["$startMs", 1000*60*60*24] }, 1000*60*60*24*7] } }
        ]
      }
    }
  },
  // 第三步:计算扣除周日后的时长
  {
    $project: {
      waitTime: 1,
      exceptSundays: { $subtract: ["$waitTime", { $multiply: ["$totalSundays", 24] }] }
    }
  }
])

核心逻辑说明

  1. 周日数量计算:
    • 从Unix纪元(1970-01-01)到目标日期的毫秒数,除以一周的毫秒数(7*24*60*60*1000)取整,得到该日期前的完整周数(每一周对应一个周日)。
    • 用结束日期的完整周数减去开始日期前一天的完整周数,即可得到区间内包含的周日总数。
  2. 时长扣除:每个周日对应24小时,用总时长减去周日数*24即可得到目标结果。

适配特殊场景

如果你的日期区间包含部分周日(比如开始于周日下午,或结束于周日上午),且需要只扣除实际占用的周日时长,可以在计算周日数后,额外判断首尾日期是否为周日,再调整扣除的小时数。但根据你的示例需求,当前写法已完全适用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:13:25