要查找 2 个日期之间的工作日总数,您可以从总天数中减去周末总数。这里的主要问题是找到周末的总数。
示例 [2016-12-23; 2017-01-01]
_Dec23___Dec24___Dec25____... ____Dec30___Dec31___Jan01___...
__Fri______Sat_____Sun______...______Fri_____Sat_____Sun_____...
如您所见,这些日期之间有 4 个周末(Dec24、Dec25、Dec31 和 Jan01)。
解决方案
以编程方式解决它的一种方法是使用 聚合框架 及其 算术 和 日期聚合运算符。
可以通过将任务拆分为 2 个子任务来完成:
- 在
startDate 和endDate(将其命名为weeksBetween)之间找出整周的数量。在上面的例子中weeksBetween = 1。
- 在
startDate + 7 * weeksBetween 和endDate(命名为left,可能是1、2、3、4、5 或6)之间找到全天 的数量。在上面的例子中left = 3(剩下的日子是周五、周六和周日)。感兴趣的是剩下几天的周末数量(将其命名为left_weekends,可能是 0,1 或 2)。在上面的例子中left_weekends = 2。
那么,周末的总数是2 * weeksBetween + left_weekends。在上面的例子中是2 * 1 + 2 = 4。
要查找left_weekends,您可以使用$dayOfWeek 日期聚合运算符。
- 如果
left 是 1,2,3,4,5 或 left_weekends = 2 如果 left 是 6(包括太阳和下一个星期六),则为太阳 dayOfWeek = 1 和 left_weekends = 1。
- 对于周一
dayOfWeek = 2 和left_weekends = 0 如果left 是1,2,3,4 或left_weekends = 1 如果left 是5 或left_weekends = 2 如果left 是6(包括下一个周六和周日)。
...
- 代表星期六
dayOfWeek = 7 和 left_weekends = 2 代表任何 left。
因此,我们可以使用以下规则:
如果remainder > 7,那么left_weekends = 2。
如果remainder = 7,则left_weekends = 1 表示周一至周六,left_weekends = 2 表示周日。
如果 remainder < 7 则 left_weekends = 0 表示周一至周六,left_weekends = 1 表示周日。
这里,remainder = dayOfWeek + left。
查询
db.dates.aggregate(
{
$project:
{
"daysBetween":
{
$add: [
{
$floor:
{
$divide: [
{ $subtract: [ "$endDate", "$startDate" ] },
1000 * 60 * 60 * 24
]
}
},
1
]
},
"startDay": { $dayOfWeek: "$startDate" },
"endDay": { $dayOfWeek: "$endDate" }
}
},
{
$project:
{
"daysBetween": "$daysBetween",
"weeksBetween": { $floor: { $divide: [ "$daysBetween", 7 ] } },
"startDay": "$startDay",
"remainder":
{
$add: [
{ $abs: { $subtract: [ "$endDay", "$startDay" ] } },
"$startDay"
]
}
}
},
{
$project:
{
"weekendsBetween":
{
$add: [
{ $multiply: [ "$weeksBetween", 2 ] },
{
$cond:
{
if: { $gt: [ "$remainder", 7 ] },
then: 2,
else:
{
$cond:
{
if: { $eq: [ "$remainder", 7 ] },
then: 1,
else: 0
}
}
}
},
{ $cond: { if: { $eq: [ "$startDay", 1 ] }, then: 1, else: 0 } }
]
},
"daysBetween": "$daysBetween"
}
},
{
$project:
{
"weekdaysBetween": { $subtract: [ "$daysBetween", "$weekendsBetween" ] }
}
}
);
示例
{ "_id": 1, "startDate": ISODate("2016-12-23T00:00:00Z"),
"endDate": ISODate("2017-01-01T00:00:00Z") }
{ "_id": 2, "startDate": ISODate("2016-12-23T00:00:00Z"),
"endDate": ISODate("2017-01-09T00:00:00Z") }
{ "_id": 3, "startDate": ISODate("2016-12-23T00:00:00Z"),
"endDate": ISODate("2017-01-18T00:00:00Z") }
结果
{ "_id": 1, "weekdaysBetween" : 6 }
{ "_id": 2, "weekdaysBetween" : 12 }
{ "_id": 3, "weekdaysBetween" : 19 }
PS 延长最后一个$project 阶段,您还可以获得两个日期之间的总天数和周末数。在测试查询之前不要忘记更改集合名称。