Skip to content

Instantly share code, notes, and snippets.

@tamunoibi
Created July 8, 2021 20:07
Show Gist options
  • Save tamunoibi/08a641adbba4797b6ec3f904ac2a7f20 to your computer and use it in GitHub Desktop.
Save tamunoibi/08a641adbba4797b6ec3f904ac2a7f20 to your computer and use it in GitHub Desktop.
/Users/tamunoibi/Documents/workspace/frontend/src/helpers/duration.js
// @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