Created
July 8, 2021 20:07
-
-
Save tamunoibi/08a641adbba4797b6ec3f904ac2a7f20 to your computer and use it in GitHub Desktop.
/Users/tamunoibi/Documents/workspace/frontend/src/helpers/duration.js
This file contains 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
// @flow | |
import Moment from "moment-timezone"; | |
import { format24as12, format12as24 } from "./functions"; | |
export const timeValidator = (time: string) => { | |
let validation; | |
const initialValidation = /^\d{1,2}([:.-]?\d{1,2})?([ ]?[A|P|a|p](M|m))?$/; | |
if (initialValidation.test(time)) { | |
let valTime = time; | |
if (/[am|pm]/i.test(valTime)) { | |
valTime = valTime.replace(" ", ""); | |
valTime = valTime.replace(".", ""); | |
valTime = valTime.replace("-", ""); | |
valTime = valTime.replace(":", ""); | |
if (valTime.includes("AM") || valTime.includes("am")) { | |
valTime = valTime.replace("am", ""); | |
valTime = valTime.replace("AM", ""); | |
let newTime; | |
switch (valTime.length) { | |
case 1: | |
if (valTime < 1) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = valTime + "am"; | |
} | |
break; | |
case 2: | |
if (valTime > 12) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = valTime + "am"; | |
} | |
break; | |
case 3: | |
const firstOne = valTime.slice(0, 1); | |
const secondTwo = valTime.slice(1, 3); | |
if (secondTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else if (secondTwo < 1) { | |
newTime = firstOne + ":" + "00" + "am"; | |
} else { | |
newTime = firstOne + ":" + secondTwo + "am"; | |
} | |
break; | |
default: | |
const firstTwo = valTime.slice(0, 2); | |
const secTwo = valTime.slice(2, 4); | |
if (firstTwo > 12) { | |
newTime = { time: valTime, error: true }; | |
} else if (secTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else if (secTwo < 1) { | |
newTime = firstTwo + "am"; | |
} else { | |
newTime = firstTwo + ":" + secTwo + "am"; | |
} | |
break; | |
} | |
return newTime; | |
} else { | |
valTime = valTime.replace("pm", ""); | |
valTime = valTime.replace("PM", ""); | |
let newTime; | |
switch (valTime.length) { | |
case 1: | |
newTime = valTime + "pm"; | |
break; | |
case 2: | |
if (valTime > 12) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = valTime + "pm"; | |
} | |
break; | |
case 3: | |
const firstOne = valTime.slice(0, 1); | |
const secondTwo = valTime.slice(1, 3); | |
if (secondTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else if (secondTwo < 1) { | |
newTime = firstOne + ":" + "00" + "pm"; | |
} else { | |
newTime = firstOne + ":" + secondTwo + "pm"; | |
} | |
break; | |
default: | |
const firstTwo = valTime.slice(0, 2); | |
const secTwo = valTime.slice(2, 4); | |
if (firstTwo > 12) { | |
newTime = { time: valTime, error: true }; | |
} else if (secTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else if (secTwo < 1) { | |
newTime = firstTwo + "pm"; | |
} else { | |
newTime = firstTwo + ":" + secTwo + "pm"; | |
} | |
break; | |
} | |
return newTime; | |
} | |
} else { | |
valTime = valTime.replace("-", ":"); | |
valTime = valTime.replace(".", ":"); | |
if (valTime.indexOf(":") === 2 && valTime.length === 4) { | |
const firstTwoChar = valTime.slice(0, 2); | |
const lastChar = valTime.slice(3, 4); | |
if (firstTwoChar > 23) { | |
return { time: valTime, error: true }; | |
} else if (lastChar > 5) { | |
return { time: valTime, error: true }; | |
} else { | |
return valTime + 0; | |
} | |
} else { | |
valTime = valTime.replace(":", ""); | |
let newTime; | |
switch (valTime.length) { | |
case 1: | |
newTime = "0" + valTime + ":00"; | |
break; | |
case 2: | |
if (valTime > 23) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = valTime + ":00"; | |
} | |
break; | |
case 3: | |
const firstOne = valTime.slice(0, 1); | |
const secondTwo = valTime.slice(1, 3); | |
if (secondTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = "0" + firstOne + ":" + secondTwo; | |
} | |
break; | |
default: | |
const firstTwo = valTime.slice(0, 2); | |
const secTwo = valTime.slice(2, 4); | |
if (firstTwo > 23) { | |
newTime = { time: valTime, error: true }; | |
} else if (secTwo > 59) { | |
newTime = { time: valTime, error: true }; | |
} else { | |
newTime = firstTwo + ":" + secTwo; | |
} | |
break; | |
} | |
return newTime; | |
} | |
} | |
} else { | |
const isXSamPM = time + "m"; | |
if ( | |
(["am", "pm"].includes(isXSamPM.slice(-2)) && isXSamPM.length === 6) || | |
isXSamPM.length === 7 | |
) { | |
return isXSamPM; | |
} else { | |
validation = { time, error: true }; | |
} | |
} | |
return validation; | |
}; | |
export const pmify = (hour) => { | |
const pm = parseInt(hour, 10); | |
let twentyfour; | |
if (pm < 12) { | |
twentyfour = pm + 12; | |
} else { | |
twentyfour = "12"; | |
} | |
return twentyfour; | |
}; | |
export const toTwentyFour = (time) => { | |
if (/[am|pm]/i.test(time)) { | |
const startLength = time.length; | |
let st; | |
let startHours; | |
let startMinutes; | |
let startMod; | |
switch (startLength) { | |
case 3: | |
startHours = time.slice(0, 1); | |
startMod = time.slice(1, 3); | |
startMod.toLocaleLowerCase() === "am" | |
? (st = "0" + startHours + ":00") | |
: (st = pmify(startHours) + ":00"); | |
break; | |
case 4: | |
startHours = time.slice(0, 2); | |
startMod = time.slice(2, 4); | |
if (startMod.toLocaleLowerCase() === "am" && startHours === "12") { | |
startHours = "00"; | |
} | |
startMod.toLocaleLowerCase() === "am" | |
? (st = startHours + ":00") | |
: (st = pmify(startHours) + ":00"); | |
break; | |
case 6: | |
startHours = time.slice(0, 1); | |
startMinutes = time.slice(2, 4); | |
startMod = time.slice(4, 6); | |
startMod.toLocaleLowerCase() === "am" | |
? (st = "0" + startHours + ":" + startMinutes) | |
: (st = pmify(startHours) + ":" + startMinutes); | |
break; | |
case 7: | |
if (time[1] === ":") { | |
startHours = "0" + time.slice(0, 1); | |
startMinutes = time.slice(2, 4); | |
startMod = time.slice(5, 7); | |
} else { | |
startHours = time.slice(0, 2); | |
startMinutes = time.slice(3, 5); | |
startMod = time.slice(5, 7); | |
if (startMod.toLocaleLowerCase() === "am" && startHours === "12") { | |
startHours = "00"; | |
} | |
} | |
startMod.toLocaleLowerCase() === "am" | |
? (st = startHours + ":" + startMinutes) | |
: (st = pmify(startHours) + ":" + startMinutes); | |
break; | |
case 8: | |
startHours = time.slice(0, 2); | |
startMinutes = time.slice(3, 5); | |
startMod = time.slice(6, 8); | |
if (startMod.toLocaleLowerCase() === "am" && startHours === "12") { | |
startHours = "00"; | |
} | |
startMod.toLocaleLowerCase() === "am" | |
? (st = startHours + ":" + startMinutes) | |
: (st = pmify(startHours) + ":" + startMinutes); | |
break; | |
default: | |
break; | |
} | |
return st; | |
} else { | |
return time; | |
} | |
}; | |
export const durationCalc = (startTime: string, endTime: string) => { | |
const startHours = startTime.slice(0, 2); | |
const endHours = endTime.slice(0, 2); | |
const startMinutes = startTime.slice(3, 5); | |
const endMinutes = endTime.slice(3, 5); | |
if ( | |
Moment() | |
.hours(startHours) | |
.minutes(startMinutes) | |
.isBefore( | |
Moment() | |
.hours(endHours) | |
.minutes(endMinutes) | |
) | |
) { | |
const difference = Moment() | |
.hours(endHours) | |
.minutes(endMinutes) | |
.diff( | |
Moment() | |
.hours(startHours) | |
.minutes(startMinutes) | |
); | |
const duration = Moment.duration(difference); | |
return duration; | |
} else if ( | |
Moment() | |
.hours(startHours) | |
.minutes(startMinutes) | |
.isSame( | |
Moment() | |
.hours(endHours) | |
.minutes(endMinutes) | |
) | |
) { | |
const st = Moment() | |
.hours(startHours) | |
.minutes(startMinutes); | |
const et = Moment() | |
.hours(endHours) | |
.minutes(endMinutes) | |
.add(1, "day"); | |
const difference = et.diff(st); | |
return Moment.duration(difference); | |
} else { | |
const altDifference = Moment() | |
.hours(24) | |
.minutes(0) | |
.diff( | |
Moment() | |
.hours(startHours) | |
.minutes(startMinutes) | |
); | |
const altEndTime = Moment() | |
.hours(endHours) | |
.minutes(endMinutes) | |
.diff( | |
Moment() | |
.hours(0) | |
.minutes(0) | |
); | |
const total = Moment.duration(altDifference).add( | |
Moment.duration(altEndTime) | |
); | |
return total; | |
} | |
}; | |
export const getDuration = (startTime: string, endTime: string) => { | |
let st; | |
let et; | |
if (/[am|pm]/i.test(startTime)) { | |
st = toTwentyFour(startTime); | |
} else { | |
st = startTime; | |
} | |
if (/[am|pm]/i.test(endTime)) { | |
et = toTwentyFour(endTime); | |
} else { | |
et = endTime; | |
} | |
if (st && et) { | |
return durationCalc(st, et); | |
} | |
return; | |
}; | |
export const getTimeSlots = (format12h) => { | |
const times = []; | |
let hour = 0; | |
let ceiling = 24; | |
while (hour < ceiling) { | |
let pushedHour; | |
// hour < 10 ? (pushedHour = "0" + hour) : (pushedHour = hour); | |
pushedHour = hour < 10 ? "0" + hour : hour; | |
let whole = pushedHour + ":00"; | |
let half = pushedHour + ":30"; | |
times.push(format12h ? format24as12(whole) : whole); | |
times.push(format12h ? format24as12(half) : half); | |
hour++; | |
} | |
return times; | |
}; | |
export const getNextHalforWhole = (time, format12h) => { | |
const st = format12h ? format12as24(time) : toTwentyFour(time); | |
const hours = st.slice(0, 2); | |
const mins = st.slice(3, 5); | |
let roundedHours; | |
let roundedMins; | |
if (mins < 30) { | |
roundedHours = hours; | |
roundedMins = "30"; | |
} else { | |
hours < 23 | |
? (roundedHours = parseInt(hours, 10) + 1) | |
: (roundedHours = "00"); | |
roundedMins = "00"; | |
} | |
let focusedTime; | |
roundedHours && roundedMins | |
? (focusedTime = roundedHours + ":" + roundedMins) | |
: (focusedTime = null); | |
return focusedTime; | |
}; | |
export const getTotalHours = (startTime, endTime, peopleCount, decimal) => { | |
const currentDuration = getDuration(startTime, endTime); | |
const totalHours = | |
(currentDuration.get("days") === 1 ? 24 : currentDuration.get("hours")) * | |
peopleCount; | |
const totalMins = decimal | |
? (currentDuration.get("minutes") * peopleCount) / 60 | |
: ((currentDuration.get("minutes") * peopleCount) / 60).toFixed(0); | |
const roundedHours = Math.round(totalHours * 10) / 10; | |
const roundedMins = Math.round(totalMins * 10) / 10; | |
return Number(roundedHours) + Number(roundedMins); | |
}; | |
export const getDefaultTimes = (type, time, minutes, format12h) => { | |
let mins; | |
let hours; | |
let hoursEnd; | |
minutes > 30 | |
? (mins = Moment() | |
.minute(0) | |
.format("mm")) | |
: (mins = Moment() | |
.minute(30) | |
.format("mm")); | |
minutes > 30 | |
? (hours = Moment(time) | |
.add(1, "h") | |
.format("HH")) | |
: (hours = Moment(time).format("HH")); | |
minutes > 30 | |
? (hoursEnd = Moment(time) | |
.add(2, "h") | |
.format("HH")) | |
: (hoursEnd = Moment(time) | |
.add(1, "h") | |
.format("HH")); | |
const whenInput = hours + ":" + mins; | |
const whenEndInput = hoursEnd + ":" + mins; | |
if (type === "start") { | |
return format12h ? format24as12(whenInput) : whenInput; | |
} else if (type === "end") { | |
return format12h ? format24as12(whenEndInput) : whenEndInput; | |
} | |
}; | |
export const getCounts = ( | |
slots, | |
dateStartTime, | |
dateEndTime, | |
count, | |
status, | |
decimal | |
) => { | |
const startTime = Moment(dateStartTime).format("HH:mm"); | |
const endTime = Moment(dateEndTime).format("HH:mm"); | |
let memberCount = 0; | |
let acceptedCount = 0; | |
let actualTime = 0; | |
slots.forEach((slot) => { | |
const count = | |
status === "CLOSED" | |
? slot.requests.length | |
: slot.limit | |
? slot.limit + | |
slot.requests.filter((r) => r.status === "ASSIGNED").length | |
: slot.requests.length - | |
slot.requests.filter( | |
(r) => | |
r.status === "DECLINED_CONFIRMED" || | |
r.status === "CANCELLED" || | |
r.status === "COVERED" || | |
r.status === "COVER_REQUESTED" || | |
r.status === "COVER_DECLINED" | |
).length; | |
memberCount = memberCount + count; | |
slot.requests.forEach((r) => { | |
const start = r.actualStart | |
? new Date(r.actualStart) | |
: new Date(dateStartTime); | |
const end = r.actualEnd ? new Date(r.actualEnd) : new Date(dateEndTime); | |
const breakTime = r.actualBreak ? r.actualBreak / 60 : 0; | |
const difference = (end - start) / (1000 * 60 * 60) - breakTime; | |
actualTime = actualTime + difference; | |
}); | |
if (status === "PUBLISHED") { | |
const memReq = slot.requests; | |
memReq.forEach((member) => { | |
if ( | |
member.status === "ACCEPTED" || | |
member.status === "CANCELLATION_REQUESTED" || | |
member.status === "ASSIGNED" | |
) | |
acceptedCount = acceptedCount + 1; | |
}); | |
} | |
}); | |
const totalHours = | |
status === "CLOSED" | |
? actualTime | |
: startTime && endTime | |
? getTotalHours(startTime, endTime, memberCount, decimal) | |
: 0; | |
const acceptedHours = | |
startTime && endTime | |
? getTotalHours(startTime, endTime, acceptedCount, decimal) | |
: ""; | |
if (count === "memberCount") return memberCount; | |
if (count === "acceptedMemberCount") return acceptedCount; | |
if (count === "hourCount") { | |
const roundedHours = Math.round(totalHours * 10) / 10; | |
return roundedHours; | |
} | |
if (count === "acceptedHourCount") return acceptedHours; | |
return; | |
}; | |
// phase this one out as it doesn't parse timezones well | |
export function getDateTime(time, date, timezone, formatAsAMPM) { | |
let hours; | |
let minutes; | |
if (formatAsAMPM || time.length > 5) { | |
hours = Moment(time, "HH:mm a").format("HH"); | |
minutes = Moment(time, "HH:mm a").format("mm"); | |
} else { | |
hours = time.slice(0, 2); | |
minutes = time.slice(3, 5); | |
} | |
let dateTime = date | |
? timezone | |
? Moment(date).tz(timezone) | |
: Moment(new Date(date)) | |
: Moment(); | |
dateTime | |
.startOf("date") | |
.add(Number(hours), "hours") | |
.add(Number(minutes), "minutes"); | |
return dateTime; | |
} | |
// this one is better | |
export function getDateTimes(startTime, endTime, date, timezone, formatAsAMPM) { | |
const d = Moment(date).format("DD-MM-YYYY"); | |
const formattedStartDate = d + ", " + startTime; | |
const formattedEndDate = d + ", " + endTime; | |
const st = Moment.tz( | |
formattedStartDate, | |
formatAsAMPM ? "DD-MM-YYYY, h:mma" : "DD-MM-YYYY, HH:mm", | |
timezone | |
).toISOString(); | |
let et = | |
endTime === "00:00" | |
? Moment.tz( | |
formattedEndDate, | |
formatAsAMPM ? "DD-MM-YYYY, h:mma" : "DD-MM-YYYY, HH:mm", | |
timezone | |
) | |
.add(1, "day") | |
.toISOString() | |
: Moment.tz( | |
formattedEndDate, | |
formatAsAMPM ? "DD-MM-YYYY, h:mma" : "DD-MM-YYYY, HH:mm", | |
timezone | |
).toISOString(); | |
if (Moment(et).isSameOrBefore(st) || !Moment(st).isSame(et, "day")) { | |
et = Moment(et) | |
.add(1, "day") | |
.toISOString(); | |
} | |
return { | |
startTime: st, | |
endTime: et, | |
}; | |
} | |
export function checkOvernight(startTime, endTime) { | |
const stH = Moment(startTime).format("HH"); | |
const stM = Moment(startTime).format("mm"); | |
const etH = Moment(endTime).format("HH"); | |
const etM = Moment(endTime).format("mm"); | |
let overnight = false; | |
if (Number(etH) < Number(stH)) { | |
overnight = true; | |
} else if (Number(etH) === Number(stH)) { | |
if (Number(etM) <= Number(stM)) { | |
overnight = true; | |
} | |
} | |
return overnight; | |
} | |
export function getScheduledHours(events, userId) { | |
let count = 0; | |
events.forEach((event) => { | |
event.slots.forEach((slot) => { | |
slot.requests.forEach((request) => { | |
const statuses = [ | |
"ACCEPTED", | |
"ASSIGNED", | |
"PENDING", | |
"CANCELLATION_REQUESTED", | |
"COVER_REQUESTED", | |
]; | |
if (statuses.includes(request.status)) { | |
if (request.user && request.user.id === userId) { | |
// also 24 hours | |
const difference = durationCalc( | |
Moment(event.startTime).format("HH:mm"), | |
Moment(event.endTime).format("HH:mm") | |
); | |
count = count + difference.asHours(); | |
} | |
} | |
}); | |
}); | |
}); | |
return Math.round(count * 10) / 10; | |
} | |
export function daysInMonth(month, year) { | |
return new Date(year, month, 0).getDate(); | |
} | |
export function convertMinsToHrsMins(mins) { | |
let h = Math.floor(mins / 60); | |
let m = mins % 60; | |
h = h < 10 ? "0" + h : h; | |
m = m < 10 ? "0" + m : m; | |
return `${h}:${m}`; | |
} | |
export function convertHrsMinsToMins(breakTime) { | |
const index = breakTime.indexOf(":"); | |
const hours = breakTime.slice(0, index); | |
const minutes = breakTime.slice(index + 1); | |
const actualBreak = Number(hours) * 60 + Number(minutes); | |
return actualBreak; | |
} | |
export function getDurations( | |
startTime, | |
endTime, | |
breakTime, | |
actualStart, | |
actualEnd, | |
actualBreakTime | |
) { | |
let eventDuration; | |
let actualDuration; | |
let eventDurationWithoutBreak; | |
let actualDurationWithoutBreak; | |
const st = Moment(startTime).format("HH:mm"); | |
const et = Moment(endTime).format("HH:mm"); | |
const eventDur = | |
startTime && endTime | |
? getDuration(st, et).subtract(breakTime, "minutes") | |
: ""; | |
eventDuration = | |
eventDur && eventDur !== "Invalid date" | |
? Math.round((eventDur.asMinutes() / 60) * 100) / 100 | |
: ""; | |
const eventDurWithoutBreak = startTime && endTime ? getDuration(st, et) : ""; | |
eventDurationWithoutBreak = | |
eventDurWithoutBreak && eventDurWithoutBreak !== "Invalid date" | |
? Math.round((eventDurWithoutBreak.asMinutes() / 60) * 100) / 100 | |
: ""; | |
const ast = actualStart | |
? Moment(actualStart).format("HH:mm") | |
: Moment(startTime).format("HH:mm"); | |
const aet = actualEnd | |
? Moment(actualEnd).format("HH:mm") | |
: Moment(endTime).format("HH:mm"); | |
const abt = | |
actualBreakTime || actualBreakTime === 0 ? actualBreakTime : breakTime; | |
const actualDur = | |
ast && aet ? getDuration(ast, aet).subtract(abt, "minutes") : ""; | |
actualDuration = | |
actualDur && actualDur !== "Invalid date" | |
? Math.round((actualDur.asMinutes() / 60) * 100) / 100 | |
: ""; | |
const actualDurWithoutBreak = ast && aet ? getDuration(ast, aet) : ""; | |
actualDurationWithoutBreak = | |
actualDurWithoutBreak && actualDurWithoutBreak !== "Invalid date" | |
? Math.round((actualDurWithoutBreak.asMinutes() / 60) * 100) / 100 | |
: ""; | |
return { | |
eventDuration, | |
actualDuration, | |
eventDurationWithoutBreak, | |
actualDurationWithoutBreak, | |
}; | |
} | |
export function getMonth(firstDay) { | |
let day = firstDay; | |
const month = []; | |
let i = 0; | |
const monthLength = daysInMonth( | |
Moment(day).format("M"), | |
Moment(day).format("YYYY") | |
); | |
while (i < monthLength) { | |
month.push(Moment(day)); | |
day = Moment(day).add(1, "days"); | |
i++; | |
} | |
return month; | |
} | |
export function getFormattedBreak(breakTime) { | |
let hours = breakTime / 60; | |
let mins = breakTime; | |
if (hours >= 1 && hours < 2) { | |
hours = 1; | |
mins = breakTime - 60; | |
} | |
let text; | |
if (hours === 1) { | |
text = `1 hr ${mins} min unpaid break`; | |
} else { | |
text = `${mins} min unpaid break`; | |
} | |
return text; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment