we would like to calculate seasonal prices based on Months via JavaScript.
Expected Return will be array with following details.
Total Days; Total Cost; Days from Jan; Days from Feb; Days from Mar; Days from Apr; Days from May; Days from June; ...
It may continue as Days from July, Days from August, Days from September
trincot‘s answer is pretty nice idea but not arranged for this. Is it possible to extend the code as expected array?
Thank you from advance.
// Utility function to facilitate day counting without timezone issues: const dayNumber = a => Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()) / (24*60*60*1000); function getPrices(allSeasons, arrival, departure) { return allSeasons.reduce( (totalPrice, {startDate, endDate, costRate}) => { let daysInSeason = Math.min(dayNumber(endDate) + 1, dayNumber(departure)) - Math.max(dayNumber(startDate), dayNumber(arrival)); return totalPrice + (daysInSeason > 0 && daysInSeason * costRate); }, 0); } const allSeasons = [ {startDate: new Date(2022, 1-1, 1), endDate: new Date(2022, 1, 0), costRate: 6500}, {startDate: new Date(2022, 2-1, 1), endDate: new Date(2022, 2, 0), costRate: 6500}, {startDate: new Date(2022, 3-1, 1), endDate: new Date(2022, 3, 0), costRate: 6500}, {startDate: new Date(2022, 4-1, 1), endDate: new Date(2022, 4, 0), costRate: 6500}, {startDate: new Date(2022, 5-1, 1), endDate: new Date(2022, 5, 0), costRate: 6500}, {startDate: new Date(2022, 6-1, 1), endDate: new Date(2022, 6, 0), costRate: 8000}, {startDate: new Date(2022, 7-1, 1), endDate: new Date(2022, 7, 0), costRate: 9000}, {startDate: new Date(2022, 8-1, 1), endDate: new Date(2022, 8, 0), costRate: 9000}, {startDate: new Date(2022, 9-1, 1), endDate: new Date(2022, 9, 0), costRate: 8000}, {startDate: new Date(2022, 10-1, 1), endDate: new Date(2022, 10, 0), costRate: 6500}, {startDate: new Date(2022, 11-1, 1), endDate: new Date(2022, 11, 0), costRate: 6500}, {startDate: new Date(2022, 12-1, 1), endDate: new Date(2022, 12, 0), costRate: 6500}, {startDate: new Date(2023, 1-1, 1), endDate: new Date(2023, 1, 0), costRate: 6500}, {startDate: new Date(2023, 2-1, 1), endDate: new Date(2023, 2, 0), costRate: 6500}, {startDate: new Date(2023, 3-1, 1), endDate: new Date(2023, 3, 0), costRate: 6500}, {startDate: new Date(2023, 4-1, 1), endDate: new Date(2023, 4, 0), costRate: 6500}, {startDate: new Date(2023, 5-1, 1), endDate: new Date(2023, 5, 0), costRate: 6500}, {startDate: new Date(2023, 6-1, 1), endDate: new Date(2023, 6, 0), costRate: 8000}, {startDate: new Date(2023, 7-1, 1), endDate: new Date(2023, 7, 0), costRate: 9000}, {startDate: new Date(2023, 8-1, 1), endDate: new Date(2023, 8, 0), costRate: 9000}, {startDate: new Date(2023, 9-1, 1), endDate: new Date(2023, 9, 0), costRate: 8000}, {startDate: new Date(2023, 10-1, 1), endDate: new Date(2023, 10, 0), costRate: 6500}, {startDate: new Date(2023, 11-1, 1), endDate: new Date(2023, 11, 0), costRate: 6500}, {startDate: new Date(2023, 12-1, 1), endDate: new Date(2023, 12, 0), costRate: 6500}, ], embarkation0 = new Date(2022, 6-1, 18), disembarkation0 = new Date(2022, 6-1, 25), totalPrice0 = getPrices(allSeasons, embarkation0, disembarkation0); console.log('7x8.000 (18,19,20,21,22,23,24) Should be 56.000 = ' + totalPrice0); embarkation1 = new Date(2022, 6-1, 25), disembarkation1 = new Date(2022, 7-1, 02), totalPrice1 = getPrices(allSeasons, embarkation1, disembarkation1); console.log('6x8.000 (25,26,27,28,29,30) + 1x9.000 (01) Should be 57.000 instead of ' + totalPrice1); embarkation2 = new Date(2022, 8-1, 20), disembarkation2 = new Date(2022, 8-1, 27), totalPrice2 = getPrices(allSeasons, embarkation2, disembarkation2); console.log('7x9.000 (20,21,22,23,24,25,26) Should be 63.000 = ' + totalPrice2); embarkation3 = new Date(2022, 8-1, 27), disembarkation3 = new Date(2022, 9-1, 03), totalPrice3 = getPrices(allSeasons, embarkation3, disembarkation3); console.log('5x9.000 (27,28,29,30,31) + 2x8.000 (01,02) Should be 61.000 instead of ' + totalPrice3); embarkation4 = new Date(2022, 9-1, 24), disembarkation4 = new Date(2022, 10-1, 01), totalPrice4 = getPrices(allSeasons, embarkation4, disembarkation4); console.log('7x8.000 (24,25,26,27,28,29,30) Should be 56.000 instead of ' + totalPrice4); embarkation5 = new Date(2023, 8-1, 26), disembarkation5 = new Date(2023, 9-1, 02), totalPrice5 = getPrices(allSeasons, embarkation5, disembarkation5); console.log('6x9.000 (26,27,28,29,30,31) + 1x8.000 (01) Should be 62.000 instead of ' + totalPrice5); embarkation6 = new Date(2024, 8-1, 28), disembarkation6 = new Date(2024, 9-1, 05), totalPrice6 = getPrices(allSeasons, embarkation6, disembarkation6); console.log('Non Exist Value 3x9.000 (28,29,30) + 4x8.000 (01,02,03,04) Should be 59.000 instead of ' + totalPrice6);
Advertisement
Answer
As your seasons correspond to calendar months, I would propose to use a simpler data structure: an array per year, each with 12 prices, one for each month in that year.
The code could be as follows:
// Utility functions const dateParts = a => [a.getFullYear(), a.getMonth(), a.getDate()]; const daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate(); function getPrices(allSeasons, arrival, departure) { let [year, month, day] = dateParts(arrival); let [year2, month2, day2] = dateParts(departure); let totalPrice = 0, totalDays = 0; const monthDays = Array(12).fill(0); for (let diff = year2*12 + month2 - (year*12 + month); diff >= 0; diff--) { const price = (allSeasons[year] ?? Object.values(allSeasons).at(-1))[month]; const days = (diff ? daysInMonth(year, month) + 1 : day2) - day; totalPrice += price * days; totalDays += days; monthDays[month] += days; day = 1; month = (month + 1) % 12; year += !month; } return [totalDays, totalPrice, ...monthDays]; } const allSeasons = { 2022: [6500, 6500, 6500, 6500, 6500, 8000, 9000, 9000, 8000, 6500, 6500, 6500], 2023: [6500, 6500, 6500, 6500, 6500, 8000, 9000, 9000, 8000, 6500, 6500, 6500], }; function test(embarkation, disembarkation, expected, msg) { let details = getPrices(allSeasons, embarkation, disembarkation); console.log(...details); if (details[1] !== expected) { console.log(msg, "Expected", expected, "but got", totalPrice); } } test(new Date(2022, 6-1, 18), new Date(2022, 6-1, 25), 56000, '7x8.000 (18,19,20,21,22,23,24)'); test(new Date(2022, 6-1, 25), new Date(2022, 7-1, 2), 57000, '6x8.000 (25,26,27,28,29,30) + 1x9.000 (01)'); test(new Date(2022, 8-1, 20), new Date(2022, 8-1, 27), 63000, '7x9.000 (20,21,22,23,24,25,26)'); test(new Date(2022, 8-1, 27), new Date(2022, 9-1, 3), 61000, '5x9.000 (27,28,29,30,31) + 2x8.000 (01,02)'); test(new Date(2022, 9-1, 24), new Date(2022, 10-1, 1), 56000, '7x8.000 (24,25,26,27,28,29,30)'); test(new Date(2023, 8-1, 26), new Date(2023, 9-1, 2), 62000, '6x9.000 (26,27,28,29,30,31) + 1x8.000 (01)'); test(new Date(2024, 8-1, 28), new Date(2024, 9-1, 5), 68000, 'Non Exist Value 4x9.000 (28,29,30,31) + 4x8.000 (01,02,03,04)'); console.log("tests completed");