Created
August 9, 2016 20:19
-
-
Save armand1m/720da2913194b692388723069f63908b to your computer and use it in GitHub Desktop.
Count a deadline date using a moment date as start point and a moment duration as the duration of hours, considering your work schedule and that you don't work at weekends, holidays
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const moment = require('moment') | |
const HOURS = { | |
WORK_START: 8, | |
LUNCH_START: 12, | |
LUNCH_END: 13, | |
WORK_END: 17 | |
} | |
const INT_LUNCH_DURATION = (HOURS.LUNCH_END - HOURS.LUNCH_START) | |
const INT_WORK_DURATION = (HOURS.WORK_END - HOURS.WORK_START - (INT_LUNCH_DURATION)) | |
const DURATIONS = { | |
LUNCH_DURATION: moment.duration(INT_LUNCH_DURATION, 'hour'), | |
HALF_WORKTIME: moment.duration(INT_WORK_DURATION / 2, 'hour'), | |
DAILY_WORKTIME: moment.duration(INT_WORK_DURATION, 'hour') | |
} | |
const WEEKEND_DAYS = [ 6, 0 ] | |
class WorktimeCounter { | |
constructor() { | |
this.holidays = [] | |
} | |
pushHoliday(holiday) { | |
if (!moment.isMoment(holiday)) | |
throw new Error("holiday must be a moment date.") | |
this.holidays.push(holiday) | |
return this.holidays | |
} | |
clearHolidays() { | |
this.holidays = [] | |
} | |
getDeadlineDate(initialDate, duration) { | |
if (!moment.isMoment(initialDate)) | |
throw new Error("initialDate must be a moment date.") | |
if (!moment.isDuration(duration)) | |
throw new Error("duration must be a moment duration object") | |
return this.adjustDate(initialDate, duration) | |
} | |
adjustDate(date, duration) { | |
var result = date.clone() | |
var remainingDuration = moment.duration(duration) | |
while (remainingDuration.as('hour')) { | |
while (this.mustSkipDate(result)) { | |
this.setNextDay(result) | |
} | |
var _duration = this.getDuration(result, remainingDuration) | |
result.add(_duration) | |
remainingDuration.subtract(_duration) | |
if (this.hasLunchtimeBetween(date, result)) { | |
result.add(DURATIONS.LUNCH_DURATION) | |
} | |
} | |
return result | |
} | |
getDuration(result, remainingDuration) { | |
var _duration = remainingDuration | |
if (remainingDuration.as('hour') >= INT_WORK_DURATION) { | |
var _durationInt = INT_WORK_DURATION | |
if (this.isBetweenWorkSchedule(result)) { | |
_durationInt = Math.abs(HOURS.WORK_END - result.hour()) | |
var _preResult = result.clone().add(moment.duration(_durationInt, 'hour')) | |
if (this.hasLunchtimeBetween(result, _preResult)) { | |
_durationInt-- | |
} | |
} | |
_duration = moment.duration(_durationInt, 'hour') | |
} | |
return _duration | |
} | |
isBetweenWorkSchedule(date) { | |
var workStart = moment(date).hour(HOURS.WORK_START) | |
var workEnd = moment(date).hour(HOURS.WORK_END) | |
return date.isBetween(workStart, workEnd) | |
} | |
mustGoToNextDay(date) { | |
return date.hour() >= HOURS.WORK_END | |
} | |
setNextDay(date) { | |
date.add(1, 'day').hour(HOURS.WORK_START) | |
} | |
hasLunchtimeBetween(initialDate, resultDate) { | |
let lunchStart = moment(resultDate).hour(HOURS.LUNCH_START) | |
return ( | |
lunchStart.isBetween(initialDate, resultDate) || | |
lunchStart.isSame(initialDate) | |
) | |
} | |
getCountOfDays(duration) { | |
return duration / DURATIONS.DAILY_WORKTIME | |
} | |
mustSkipDate(date) { | |
return this.isWeekend(date) || | |
this.isHoliday(date) || | |
this.mustGoToNextDay(date) | |
} | |
isWeekend(date) { | |
for (var i = 0; i < WEEKEND_DAYS.length; i++) | |
if (date.day() == WEEKEND_DAYS[i]) | |
return true | |
return false | |
} | |
isHoliday(date) { | |
for (var i = 0; i < this.holidays.length; i++) | |
if (date.isSame(this.holidays[i], 'day')) | |
return true | |
return false | |
} | |
} | |
module.exports = WorktimeCounter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment