Skip to content

Instantly share code, notes, and snippets.

@armand1m
Created August 9, 2016 20:19
Show Gist options
  • Save armand1m/720da2913194b692388723069f63908b to your computer and use it in GitHub Desktop.
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
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