How to merge days with similar opening hours - javascript

I'm trying to write a javascript function to merge days with similar opening hours of a store together. For example, if we have:
"hours": [
"Friday 11:00am - 3:00pm, 5:00pm - 10:00pm",
"Monday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Saturday 12:00pm - 10:00pm",
"Sunday 12:00pm - 9:30pm",
"Thursday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Tuesday 11:00am - 3:00pm, 5:00pm - 9:30pm",
"Wednesday 11:00am - 3:00pm, 5:00pm - 9:30pm"
],
I want the code to simplify it to:
"hours": [
"Mo-Sa 11:00-14:30",
"Mo-Th 17:00-21:30",
"Fr-Sa 17:00-22:00"
],
Is there a way of accomplishing this without a long list of if/else or case statements?

Go functional and save a lot of mess.
Assuming that this is your data:
var data = [
{day: "Mon", open: 900, close: 1700},
{day: "Tue", open: 900, close: 1700},
{day: "Wed", open: 700, close: 1700},
{day: "Thu", open: 900, close: 1700},
{day: "Fri", open: 900, close: 1700},
{day: "Sat", open: 900, close: 1900},
{day: "Sun", open: 900, close: 1900},
];
You can simply reduce the array to a merged array in 6 lines of code:
var merged = data.reduce(function(preVal, curVal) {
var last = preVal[preVal.length - 1];
if (last && last.open == curVal.open && last.close == curVal.close) {
last.endDay = curVal.day;
} else {
preVal.push(curVal);
}
return preVal;
}, []);
And just in case for debugging:
for (var i in merged) {
var m = merged[i];
var endDay = m.endDay ? " to " + m.endDay : "";
console.log(m.day + endDay + " " + m.open + "-" + m.close);
}
BONUS Now, if you have to convert merged into a different format (e.g., something that you need to print on the screen) you can go functional again and map the merged into whatever format you want:
var mergedNewFormat = merged.map(function(v) {
return {
days: [v.day, v.endDay ? v.endDay : v.day],
hours: [v.open, v.close],
};
});

I would suggest breaking your data down into a more structured format than what you currently have specified in your comments such as:
var data = [
{ day: "Mon", hours: "11:00 AM to 10:30 PM" },
{ day: "Thu", hours: "11:00 AM to 10:30 PM" },
{ day: "Tue", hours: "11:00 AM to 10:30 PM" },
{ day: "Wed", hours: "11:00 AM to 10:32 PM" },
{ day: "Fri", hours: "11:00 AM to 10:00 PM" },
{ day: "Sat", hours: "11:00 AM to 10:00 PM" },
{ day: "Sun", hours: "11:00 AM to 10:30 PM" }
];
Now you can iterate over the days and group by identical hours like this:
function collapseHours(data) {
var collapsed = [];
var idx = -1;
for(var i=0; i<data.length; i++) {
var day = data[i];
if(idx == -1 || collapsed[idx].hours != day.hours) {
collapsed.push({days:[day.day],hours:day.hours});
idx++;
} else {
collapsed[idx].days.push(day.day);
}
}
return collapsed;
}
This collapseHours(data) would produce the following:
[
{"days":["Mon","Thu","Tue"],"hours":"11:00 AM to 10:30 PM"},
{"days":["Wed"],"hours":"11:00 AM to 10:32 PM"},
{"days":["Fri","Sat"],"hours":"11:00 AM to 10:00 PM"},
{"days":["Sun"],"hours":"11:00 AM to 10:30 PM"}
];
Now you can pretty print your hours like this:
function prettyPrintHours(collapsed) {
var lines = [];
for(var i=0; i<collapsed.length; i++) {
var line = collapsed[i];
var days = line.days;
if(days.length == 1) {
lines.push(days[0]+" "+line.hours);
} else {
lines.push(days[0]+"-"+days[days.length-1]+" "+line.hours);
}
}
return lines;
}
Which will produce:
[
"Mon-Tue 11:00 AM to 10:30 PM",
"Wed 11:00 AM to 10:32 PM",
"Fri-Sat 11:00 AM to 10:00 PM",
"Sun 11:00 AM to 10:30 PM"
]
Given these two functions it should be relatively simple to customize the data format and output formatting to your exact needs.

Related

Generating 7 days in a week as formatted object

so I am using the momentJS library as the moment to create an array of 7 days in a week like this:
const moment = require('moment')
var startOfWeek = moment().startOf('week');
var endOfWeek = moment().endOf('week');
var days = [];
var day = startOfWeek;
while (day <= endOfWeek) {
days.push(day.format("MMMM ddd DD, YYYY "));
day = day.clone().add(1, 'd');
}
console.log(days);
And the result return an array of 7 days a week like this:
["December Sun 25, 2022 ","December Mon 26, 2022 ", "December Tue 27, 2022 " , "December Wed 28, 2022 ", "December Thu 29, 2022 ", "December Fri 30, 2022 ", "December Sat 31, 2022 "]
But the result that I look for is something like this:
const weekday = [
{
day: Mon,
date: 26
},
{
day: Tue,
date: 27
},
{
day: Wed,
date: 28
},
{
day: Thu,
date: 26
},
{
day: Fri,
date: 26
},
{
day: Sat,
date: 26
},
]
I am stuck on how to convert the data, could anyone able to help me ? Thanks
Without momentjs, you can use toLocaleDateString and other native Date methods to achieve the result:
const day = new Date(); // Today
day.setDate(day.getDate() - day.getDay() - 1); // Most recent Saturday (not today)
const weekday = Array.from({length: 7}, () => (
day.setDate(day.getDate() + 1), {
day: day.toLocaleDateString("en-US", { weekday: "short" }),
date: day.getDate(),
}
));
console.log(weekday);
If you wish to keep the original output to use elsewhere and not modify the original code, you can map over the days array and construct a new array based on the formatted string (converting to an integer as necessary).
const days = ["December Sun 25, 2022 ", "December Mon 26, 2022 ", "December Tue 27, 2022 ", "December Wed 28, 2022 ", "December Thu 29, 2022 ", "December Fri 30, 2022 ", "December Sat 31, 2022 "]
const weekday = days.map((formattedDate) => {
const [_, day, dateString] = formattedDate.split(" ");
return {
day,
date: parseInt(dateString)
};
});
console.log(weekday);
Alternatively, you can modify your original code
//const moment = require('moment')
const startOfWeek = moment().startOf('week');
const endOfWeek = moment().endOf('week');
// uncomment if you still want `days`
// const days = [];
const weekday = [];
let day = startOfWeek;
while (day <= endOfWeek) {
// days.push(day.format("MMMM ddd DD, YYYY "));
weekday.push({ day: day.format("ddd"), date: day.date() });
day = day.clone().add(1, 'd');
}
console.log(weekday);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>

Sort array of days in ascending order

I have an array that contains unique strings of day names. The day names will be in random order. - eg:
["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"]
I want to use javascript to sort that array so that it will be in ascending order.
["Wed 3pm", "Sat 10am", "Sat 4pm", "Sun 10am", "Sun 4pm"]
Can anybody suggest the best way to do that?
Thank you
You can create a object with days names as keys and values increasing from 1 to 7.
Create a helper function which takes second part of string i.e 3pm,10am.. as input and add 12 to result if its pm
Also divide the result by 24 so first sort should happen on days.
Use the sort() function and for each value add the time index(which will be always less than 1) to the day index(1,2,3...) and subtract it for both value.
const arr = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"];
function getTime(str){
let time = str.slice(0,-2);
let isAm = str.includes('am');
return (isAm ? +time : +time + 12)/24
}
function sortTime(arr){
let days = {
Mon:1,
Tue:2,
Wed:3,
Thur:4,
Fri:5,
Sat:6,
Sun:7
}
return arr.slice().sort((a,b) => {
let [day1,time1] = a.split(' ');
let [day2,time2] = b.split(' ');
return (days[day1] + getTime(time1)) - (days[day2] + getTime(time2))
})
}
console.log(sortTime(arr))
You could take an object for the values of the day and sort by the time.
const
getTime = string => {
var [day, hour, meridian] = string.match(/^(\D{3}) (\d+)(am|pm)/).slice(1),
days = { Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6, Sun: 7 };
return days[day] * 24 + +hour + (meridian === 'pm' && 12) + (hour === '12' && -12);
};
var array = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm", "Sat 12pm", "Sat 12am"];
array.sort((a, b) => getTime(a) - getTime(b));
console.log(array);
You can use the combination of map and sort. Here I am converting time in 24 Hours format for easy comparison of numbers.
var array = ["Sun 10am", "Sat 4pm", "Sat 10am", "Wed 3pm", "Sun 4pm"],
mapping = { Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6, Sun: 7 },
result = array
.map((time, i) => {
const hour = parseInt(time.split(" ")[1], 10);
const hour24 = time.indexOf("am") > -1 ? hour : hour + 12;
return {
index: i,
day: mapping[time.split(" ")[0]],
hour24
}
})
.sort((a, b) => a.day - b.day || a.hour24 - b.hour24)
.map(({
index
}) => array[index]);
console.log(result);

How to use different arrays for different days?

I have two arrays both of sets of dates and times for a school bell schedule. The school uses a different bell schedule on Wednesdays. How do I pull the array for Wednesday only on Wednesday and allow for the other array to work on every day besides Wednesday? This code will take the start and end times in the array and if the time is between the start and end times it will take the time between the two and display a countdown timer.
//start of code
var d = new Date(2019);
function getTimeRemaining(endtime) {
var t = Date.parse(endtime) - Date.parse(new Date());
var seconds = Math.floor((t / 1000) % 60);
var minutes = Math.floor((t / 1000 / 60) % 60);
return {
'total': t,
'minutes': minutes,
'seconds': seconds
};
}
var myVar;
myVar = setInterval(function(){window.location.reload(1);}, 1000);
function myStopFunction() {
clearTimeout(myVar);
}
function initializeClock(id, endtime) {
var clock = document.getElementById(id);
clock.style.display = 'block';
var minutesSpan = clock.querySelector('.minutes');
var secondsSpan = clock.querySelector('.seconds');
function updateClock() {
var t = getTimeRemaining(endtime);
minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);
}
updateClock();
var timeinterval = setInterval(updateClock, 1000);
}
var windowObjectReference;
function openRequestedPopup() {
windowObjectReference = window.open(
"file:///C:/Users/Darren%20Blount/OneDrive/COUNTDOWN/5_timer.html",
"DescriptiveWindowName", 'height=30000,width=40000, left=40000, resizable=yes,scrollbars=yes,toolbar=yes, status=yes');
var monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November",
"December"];
var d = new Date();
var currentMonth = monthNames[d.getMonth()];
var DayNames = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
"12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
"24", "25", "26", "27", "28", "29", "30", "31"];
var g = new Date();
var currentDay = DayNames[g.getDay()];
var wednesday /* Havenot worked into code*/= [
// Daily Bell Schedule
['Oct 30, 2018 7:50:49', 'Oct 30, 2018 8:00:49'],
//AAP
['Oct 30, 2018 9:29:49', 'Oct 30, 2018 9:34:49'],
//1st Block - 2nd Block
['Oct 30, 2018 9:58:49', 'Oct 30, 2018 10:03:49'],
//2nd Block - 1st Half 3rd Block
['Oct 30, 2018 11:49:49', 'Oct 30, 2018 11:37:49'],
//1st Lunch - 3rd Block
['Oct 30, 2018 12:02:49', 'Oct 30, 2018 12:07:49'],
//2nd Lunch - 2nd Half of 3rd Block
['Oct 30, 2018 12:42:49', 'Oct 30, 2018 12:47:49'],
//3rd Block - 4th Block
['Oct 30, 2018 13:36:49', 'Oct 30, 2018 13:41:49']
];
const schedule /*Everyday*/= [
['Sep 11, 2018 7:50:49', 'Sep 11, 2018 8:00:49'],
//AAP
['Sep 11, 2018 9:29:49', 'Sep 11, 2018 9:34:49'],
//1st Block - 2nd Block
['Sep 11, 2018 9:58:49', 'Sep 11, 2018 10:03:49'],
//2nd Block - 1st Half 3rd Block
['Sep 11, 2018 11:49:49', 'Sep 11, 2018 11:37:49'],
//1st Lunch - 3rd Block
['Sep 11, 2018 12:02:49', 'Sep 11, 2018 12:07:49'],
//2nd Lunch - 2nd Half of 3rd Block
['Sep 11, 2018 12:42:49', 'Sep 11, 2018 12:47:49'],
//3rd Block - 4th Block
['Sep 11, 2018 1:36:49', 'Sep 11, 2018 1:41:49']
];
const schedule = [
[currentMonth + currentDay + '2019 13:40:00', currentMonth + currentDay
+ '2019 14:30:00']
]
for(let i=0; i<schedule.length; i++){
// pull them straight into Date objects
const startDate = new Date(schedule[i][0]);
const endDate = new Date(schedule[i][1]);
// Make a new Date for setting it for today, then set the hours based off
the schedule
let startTime = new Date();
startTime.setHours(startDate.getHours(), startDate.getMinutes(),
startDate.getSeconds());
let endTime = new Date();
endTime.setHours(endDate.getHours(), endDate.getMinutes(),
endDate.getSeconds());
// Easier way to just get the ms and then the same check
const currentMs = Date.now();
if(endTime.valueOf() > currentMs && currentMs >= startTime.valueOf() ){
initializeClock('clockdiv', endDate);
openRequestedPopup();
myStopFunction();
setInterval(function(){window.location.reload(5);}, 306000);
setTimeout(function () { windowObjectReference.close();}, 305000);
}
}
To achieve expected result , below option of getting current day using getDay()
(starts with Sunday - 0 and for Wednesday it is 3)
var d = new Date();
var today = d.getDay();
var wednesday = [
// Daily Bell Schedule
['Oct 30, 2018 7:50:49', 'Oct 30, 2018 8:00:49'],
//AAP
['Oct 30, 2018 9:29:49', 'Oct 30, 2018 9:34:49'],
//1st Block - 2nd Block
['Oct 30, 2018 9:58:49', 'Oct 30, 2018 10:03:49'],
//2nd Block - 1st Half 3rd Block
['Oct 30, 2018 11:49:49', 'Oct 30, 2018 11:37:49'],
//1st Lunch - 3rd Block
['Oct 30, 2018 12:02:49', 'Oct 30, 2018 12:07:49'],
//2nd Lunch - 2nd Half of 3rd Block
['Oct 30, 2018 12:42:49', 'Oct 30, 2018 12:47:49'],
//3rd Block - 4th Block
['Oct 30, 2018 13:36:49', 'Oct 30, 2018 13:41:49']
];
var everyday = [
['Sep 11, 2018 7:50:49', 'Sep 11, 2018 8:00:49'],
//AAP
['Sep 11, 2018 9:29:49', 'Sep 11, 2018 9:34:49'],
//1st Block - 2nd Block
['Sep 11, 2018 9:58:49', 'Sep 11, 2018 10:03:49'],
//2nd Block - 1st Half 3rd Block
['Sep 11, 2018 11:49:49', 'Sep 11, 2018 11:37:49'],
//1st Lunch - 3rd Block
['Sep 11, 2018 12:02:49', 'Sep 11, 2018 12:07:49'],
//2nd Lunch - 2nd Half of 3rd Block
['Sep 11, 2018 12:42:49', 'Sep 11, 2018 12:47:49'],
//3rd Block - 4th Block
['Sep 11, 2018 1:36:49', 'Sep 11, 2018 1:41:49']
];
if(today ===3){
console.log("Wednesday", wednesday)
}else{
console.log("not wednesday", everyday)
}

Modifying JS Array based on some conditions

var arr = [{"Event_code":"AB-001","Interest_area":"Arts","Start_time":"9:00 AM","End_time":"3:00 PM","Session_type":"Course information session"},{"Event_code":"AB-002","Interest_area":"Arts","Start_time":"12:30 PM","End_time":"1:00 PM","Session_type":"Course information session"},{"Event_code":"AB-003","Interest_area":"","Start_time":"9:00 AM","End_time":"3:00 PM","Session_type":"Course information session"},{"Event_code":"AB-004","Interest_area":"Business","Start_time":"10:30 AM","End_time":"11:00 AM","Session_type":"Course information session"},{"Event_code":"AB-005","Interest_area":"General Interest","Start_time":"9:00 AM","End_time":"1:30 PM","Session_type":"Experience"},{"Event_code":"AB-006","Interest_area":"Environment , Business ","Start_time":"11:00 AM","End_time":"11:30 AM","Session_type":"Course information session"}];
var st = {};
arr.forEach(o => {
if(st[o.Start_time]) o.clash = "yes";
else st[o.Start_time] = o.Start_time;
var diff = ( new Date("1970-1-1 " + o.End_time) - new Date("1970-1-1 " + o.Start_time) ) / 1000 / 60 / 60;
//console.log(diff); // hours
if (diff > 5){
o.duration = "Full day event";
}
});
console.log(arr);
What I am trying to do is add 2 key value pairs based on 2 conditions ..
Cond 1. Add "Clash":" Yes" if 2 events have a same start time
Cond 2: Add "Duration:"Full Day event" if "Start time" and "end time" have a difference of more than 5 hours.
The above code is not printing "clash":"Yes" pair.
This question has helped me greatly with Condition 1. I just want to add Condition 2 now.
For setting clash, you could take an object with start time and the actual index.
If another event starts at the time, set clash to both of the objects.
var array = [{ Event_code: "AB-001", Interest_area: "Arts", Start_time: "9:00 AM", End_time: "3:00 PM", Session_type: "Course information session" }, { Event_code: "AB-002", Interest_area: "Arts", Start_time: "12:30 PM", End_time: "1:00 PM", Session_type: "Course information session" }, { Event_code: "AB-003", Interest_area: "", Start_time: "9:00 AM", End_time: "3:00 PM", Session_type: "Course information session" }, { Event_code: "AB-004", Interest_area: "Business", Start_time: "10:30 AM", End_time: "11:00 AM", Session_type: "Course information session" }, { Event_code: "AB-005", Interest_area: "General Interest", Start_time: "9:00 AM", End_time: "1:30 PM", Session_type: "Experience" }, { Event_code: "AB-006", Interest_area: "Environment, Business", Start_time: "11:00 AM", End_time: "11:30 AM", Session_type: "Course information session" }],
clash = Object.create(null);
array.forEach((o, i, a) => {
var diff = (new Date("1970-1-1 " + o.End_time) - new Date("1970-1-1 " + o.Start_time)) / 1000 / 60 / 60;
//console.log(diff); // hours
if (diff > 5) {
o.duration = "Full day event";
}
if (o.Start_time in clash) {
a[clash[o.Start_time]].clash = true; // set first found
o.clash = true; // set actual item
return;
}
clash[o.Start_time] = i; // save index
});
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I changed your code a bit and here is new working code

jQuery Add Array Values

I have a json given below
0 : {car_rental_id: "6007", sharing_schedule: "9:00 AM", booked_cars: '1', woo_order_id: "6421", woo_status: "on-hold" }
1 : {car_rental_id: "6007", sharing_schedule: "9:00 AM", booked_cars: '3', woo_order_id: "6424", woo_status: "pending" }
2 : {car_rental_id: "6007", sharing_schedule: "10:00 AM", booked_cars: '5', woo_order_id: "6427", woo_status: "pending"}
The goal here is to get the total number of booked_cars on a time. So according to this json. I should get
4 bookings for 9:00 AM and 5 bookings for 10:00 AM.
How do I achieve that?
var test = [{
car_rental_id: "6007",
sharing_schedule: "9:00 AM",
woo_order_id: "6421",
woo_status: "on-hold",
booked_cars: '1'
}, {
car_rental_id: "6007",
sharing_schedule: "9:00 AM",
woo_order_id: "6424",
woo_status: "pending",
booked_cars: '3'
}, {
car_rental_id: "6007",
sharing_schedule: "10:00 AM",
woo_order_id: "6427",
woo_status: "pending",
booked_cars: '5'
}];
var carsBookedByTime = test.reduce(function(collection, element){
var bookedCars = parseInt(element.booked_cars);
//initialize total in the collection if it does not exist
if (!collection[element.sharing_schedule]) collection[element.sharing_schedule] = 0;
collection[element.sharing_schedule] += bookedCars;
return collection;
}, {});
console.log(carsBookedByTime);
You could change it to something like that.
var values = window.confirmedBookings.reduce(function(prev, current) {
if(!prev[current.sharing_schedule]) prev[current.sharing_schedule] = 0;
prev[current.sharing_schedule] += Number(current.booked_cars);
return prev;
}, {})
#edit: updated an answer to fit a question.
You appear to be asking for :
window.totalBooked = {};
$.each(window.confirmedBookings, function(index, value) {
console.log(value.booked_cars);
window.totalBooked[value.sharing_schedule] = (window.totalBooked[value.sharing_schedule] || 0) + +value.booked_cars;
});
or, slightly simpler :
window.totalBooked = window.confirmedBookings.reduce(function(obj, value) {
obj[value.sharing_schedule] = (obj[value.sharing_schedule] || 0) + +value.booked_cars;
return obj;
}, {});
DEMO

Categories