让我们先来看最简单的情况:我们的工人只工作了一天。一个时间表是额外的时间一夜之间看起来是这样的:
extra paid ---|-- regular paying ---------|---- extra paid ---
|--------- working time -----------------------------|
|--- 1 -------|--------------- 2 ----------------|---- 3 ---|
如果额外的时间只是一天,实际上更简单:
|----------- regular paying -------|------ extra paid ----|----|
|------ working time -----------------|
|----- 1 -----------------------------|- 2 -|
所以我们只需要计算工人工作的三个不同范围,所有单位都以分钟为单位:
function paymentRange(payment: number, start: number, end: number) {
return function calculatePayment(startWorking: number, endWorking: number) {
if(start < end) {
const rangeStart = Math.max(start, startWorking);
const rangeEnd = Math.min(end, endWorking);
return Math.max(rangeEnd - rangeStart, 0) / 60 * payment;
} else {
const morning = Math.max(end - startWorking, 0);
const evening = Math.max(endWorking - start, 0)
return (morning + evening) / 60 * payment;
}
}
}
现在我们只需要一种组合多种付款的方法:
function combinedPayment(...payments) {
return (start, end) => payments.reduce((sum, payment) => sum + payment(start, end), 0);
}
因此,要获得一天的付款,我们可以这样做:
const calculatePayment = combinedPayment(
paymentRange(3/*$*/, 22/*h*/ * 60, 2/*h*/ * 60 + 30/*min*/),
paymentRange(15/*$*/, 0/*min*/, 24/*h*/ * 60)
);
// If he worked from 1h to 22h:
calculatePayment(1/*h*/ * 60, 22/*h*/ * 60)
现在我们只需要将日期范围划分为天数,然后计算天数的付款:
const dateToMins = date => date.getHours() * 60 + date.getMinutes();
const toWholeDay = date => new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
const min = (a, b) => new Date(Math.min(+a, +b));
const max = (a, b) => new Date(Math.max(+a, +b));
function paymentForDateRange(payment, start: Date, end: Date) {
let pay = 0;
let today = toWholeDay(start);
while(+today < +end) {
const nextDay = new Date(today + 1000 * 60 * 60 * 24);
const startWorking = max(start, today);
const endWorking = min(end, nextDay);
pay += payment(dateToMins(startWorking), dateToMins(endWorking));
today = nextDay;
}
return pay;
}
所以我们终于可以做到:
paymentForDateRange(calculatePayment, new Date(), new Date())
PS:我无法测试其中的每一个部分,它可能无法完全工作